arch/sparc add initial support for S698PM
This commit is contained in:
parent
b3ff4ce301
commit
868de3ca4b
27 changed files with 6705 additions and 6 deletions
|
|
@ -43,7 +43,7 @@ config ARCH_CHIP_S698PM
|
|||
select ARCH_HAVE_TESTSET
|
||||
select ARCH_HAVE_SERIAL_TERMIOS
|
||||
---help---
|
||||
Microchip S698PM (ARCH_SPARC_V8)
|
||||
ORBITA Sailing S698PM (ARCH_SPARC_V8)
|
||||
|
||||
endchoice
|
||||
|
||||
|
|
|
|||
206
arch/sparc/include/s698pm/irq.h
Normal file
206
arch/sparc/include/s698pm/irq.h
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/include/s698pm/irq.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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* This file should never be included directed but, rather, only indirectly
|
||||
* through nuttx/irq.h
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_SPARC_INCLUDE_S698PM_IRQ_H
|
||||
#define __ARCH_SPARC_INCLUDE_S698PM_IRQ_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Interrupt Sources The interrupt source numbers directly map to the trap
|
||||
* type and to the bits used in the Interrupt Clear, Interrupt Force,
|
||||
* Interrupt Mask, and the Interrupt Pending Registers.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ARCH_CHIP_S698PM)
|
||||
|
||||
#define S698PM_IRQREG_BASE 0x80000200
|
||||
|
||||
#define S698PM_IRQREG_ILEVEL (S698PM_IRQREG_BASE + 0)
|
||||
#define S698PM_IRQREG_IPEND (S698PM_IRQREG_BASE + 0x4)
|
||||
#define S698PM_IRQREG_IFORCE (S698PM_IRQREG_BASE + 0x8)
|
||||
#define S698PM_IRQREG_ICLEAR (S698PM_IRQREG_BASE + 0xc)
|
||||
#define S698PM_IRQREG_MPSTATUS (S698PM_IRQREG_BASE + 0x10)
|
||||
#define S698PM_IRQREG_BROADCAST (S698PM_IRQREG_BASE + 0x14)
|
||||
|
||||
#define S698PM_IRQREG_P0_MASK (S698PM_IRQREG_BASE + 0x40)
|
||||
#define S698PM_IRQREG_P1_MASK (S698PM_IRQREG_BASE + 0x44)
|
||||
#define S698PM_IRQREG_P2_MASK (S698PM_IRQREG_BASE + 0x48)
|
||||
#define S698PM_IRQREG_P3_MASK (S698PM_IRQREG_BASE + 0x4c)
|
||||
|
||||
#define S698PM_IRQREG_P0_FORCE (S698PM_IRQREG_BASE + 0x80)
|
||||
#define S698PM_IRQREG_P1_FORCE (S698PM_IRQREG_BASE + 0x84)
|
||||
#define S698PM_IRQREG_P2_FORCE (S698PM_IRQREG_BASE + 0x88)
|
||||
#define S698PM_IRQREG_P3_FORCE (S698PM_IRQREG_BASE + 0x8c)
|
||||
|
||||
#define S698PM_IRQREG_P0_EXTACK (S698PM_IRQREG_BASE + 0xc0)
|
||||
#define S698PM_IRQREG_P1_EXTACK (S698PM_IRQREG_BASE + 0xc4)
|
||||
#define S698PM_IRQREG_P2_EXTACK (S698PM_IRQREG_BASE + 0xc8)
|
||||
#define S698PM_IRQREG_P3_EXTACK (S698PM_IRQREG_BASE + 0xcc)
|
||||
|
||||
#define S698PM_IRQ_FIRST 0x00
|
||||
|
||||
#define S698PM_IRQ_RESET 0x00
|
||||
#define S698PM_IRQ_INST_ACC_EXCEPTION 0x01
|
||||
#define S698PM_IRQ_ILL_INST 0x02
|
||||
#define S698PM_IRQ_PRIVELEGE_INST 0x03
|
||||
#define S698PM_IRQ_FP_DISABLED 0x04
|
||||
#define S698PM_IRQ_WINDOW_OVERFLOW 0x05
|
||||
#define S698PM_IRQ_WINDOW_UNDERFLOW 0x06
|
||||
#define S698PM_IRQ_ADD_NOT_ALIGNED 0x07
|
||||
#define S698PM_IRQ_ADD_FP_EXCEPTION 0x08
|
||||
#define S698PM_IRQ_DATA_ACC_EXCEPTION 0x09
|
||||
#define S698PM_IRQ_TAG_OVERFLOW 0x0A
|
||||
#define S698PM_IRQ_HW_UNDEFINED_0B 0x0B
|
||||
#define S698PM_IRQ_HW_UNDEFINED_0C 0x0C
|
||||
#define S698PM_IRQ_HW_UNDEFINED_0D 0x0D
|
||||
#define S698PM_IRQ_HW_UNDEFINED_0E 0x0E
|
||||
#define S698PM_IRQ_HW_UNDEFINED_0F 0x0F
|
||||
#define S698PM_IRQ_HW_UNDEFINED_10 0x10
|
||||
|
||||
#define S698PM_IRQ_FIRST_INT 0x11
|
||||
|
||||
#define S698PM_IRQ_AHB_ERROR 0x11
|
||||
#define S698PM_IRQ_UART_1_RX_TX 0x12
|
||||
#define S698PM_IRQ_UART_2_RX_TX 0x13
|
||||
#define S698PM_IRQ_LOCKTIMER12 0x14
|
||||
#define S698PM_IRQ_ETHERNET 0x15
|
||||
#define S698PM_IRQ_TIMER1 0x16
|
||||
#define S698PM_IRQ_TIMER2 0x17
|
||||
#define S698PM_IRQ_TIMER3 0x18
|
||||
#define S698PM_IRQ_TIMER4 0x19
|
||||
#define S698PM_IRQ_1553B 0x1A
|
||||
#define S698PM_IRQ_EXTENDED 0x1B
|
||||
#define S698PM_IRQ_EXTERNAL_12 0x1C
|
||||
#define S698PM_IRQ_EXTERNAL_13 0x1D
|
||||
#define S698PM_IRQ_EXTERNAL_14 0x1E
|
||||
#define S698PM_IRQ_EXTERNAL_15 0x1F
|
||||
|
||||
#define S698PM_IRQ_LAST_INT 0x1F
|
||||
|
||||
#define S698PM_IRQ_HW_UNDEFINED_20 0x20
|
||||
#define S698PM_IRQ_HW_UNDEFINED_21 0x21
|
||||
#define S698PM_IRQ_HW_UNDEFINED_22 0x22
|
||||
#define S698PM_IRQ_HW_UNDEFINED_23 0x23
|
||||
|
||||
#define S698PM_IRQ_CP_DISABLED 0x24
|
||||
|
||||
#define S698PM_IRQ_HW_UNDEFINED_25 0x25
|
||||
#define S698PM_IRQ_HW_UNDEFINED_26 0x26
|
||||
#define S698PM_IRQ_HW_UNDEFINED_27 0x27
|
||||
|
||||
#define S698PM_IRQ_CP_EXCEPTION 0x28
|
||||
|
||||
#define S698PM_IRQ_HW_UNDEFINED_29 0x29
|
||||
#define S698PM_IRQ_HW_UNDEFINED_7F 0x7F
|
||||
|
||||
#define S698PM_IRQ_SW_SYSCALL_TA0 0x80
|
||||
#define S698PM_IRQ_SW_UNDEFINED_81 0x81
|
||||
#define S698PM_IRQ_SW_UNDEFINED_82 0x82
|
||||
#define S698PM_IRQ_SW_FLUSH_WINDOWS 0x83
|
||||
|
||||
#define S698PM_IRQ_SW_UNDEFINED_84 0x84
|
||||
#define S698PM_IRQ_SW_UNDEFINED_85 0x85
|
||||
#define S698PM_IRQ_SW_UNDEFINED_86 0x86
|
||||
#define S698PM_IRQ_SW_UNDEFINED_87 0x87
|
||||
#define S698PM_IRQ_SW_SYSCALL_TA8 0x88
|
||||
|
||||
#define S698PM_IRQ_SW_SYSCALL_IRQDIS 0x89
|
||||
#define S698PM_IRQ_SW_SYSCALL_IRQEN 0x8A
|
||||
|
||||
#define S698PM_IRQ_SW_UNDEFINED_8B 0x8B
|
||||
#define S698PM_IRQ_SW_UNDEFINED_FF 0xFF
|
||||
|
||||
#define S698PM_IRQ_LAST 0xFF
|
||||
|
||||
#define S698PM_IRQ_SPW1 0x100
|
||||
#define S698PM_IRQ_SPW2 0x101
|
||||
#define S698PM_IRQ_SPW3 0x102
|
||||
#define S698PM_IRQ_SPW4 0x103
|
||||
#define S698PM_IRQ_CCSDS 0x104
|
||||
#define S698PM_IRQ_EXTERNAL 0x105
|
||||
#define S698PM_IRQ_USBHOST 0x106
|
||||
#define S698PM_IRQ_UART_3_RX_TX 0x107
|
||||
#define S698PM_IRQ_CAN1 0x108
|
||||
#define S698PM_IRQ_CAN2 0x109
|
||||
#define S698PM_IRQ_CCSDS_CODE 0x10A
|
||||
#define S698PM_IRQ_CCSDS_DECODE 0x10B
|
||||
#define S698PM_IRQ_I2C 0x10C
|
||||
#define S698PM_IRQ_SPI 0x10D
|
||||
#define S698PM_IRQ_UART_4_RX_TX 0x10E
|
||||
#define S698PM_IRQ_L2CACHE 0x10F
|
||||
|
||||
#define NR_IRQS 272
|
||||
#define S698PM_EXTENDED_IRQ 11
|
||||
#define S698PM_IPI_VECTOR 14
|
||||
#define S698PM_IPI_IRQ S698PM_IRQ_EXTERNAL_14
|
||||
#define S698PM_EXTENDED_START 16
|
||||
#define S698PM_CPUINT_MAX 32
|
||||
|
||||
#else
|
||||
#error "Unrecognized chip"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Inline functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_SPARC_INCLUDE_S698PM_IRQ_H */
|
||||
|
|
@ -210,7 +210,6 @@ uintptr_t up_intstack_alloc(void);
|
|||
uintptr_t up_intstack_top(void);
|
||||
#endif
|
||||
|
||||
|
||||
/* Chip-specific functions **************************************************/
|
||||
|
||||
/* Chip specific functions defined in arch/sparc/src/<chip> */
|
||||
|
|
|
|||
135
arch/sparc/src/s698pm/Kconfig
Normal file
135
arch/sparc/src/s698pm/Kconfig
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
if ARCH_CHIP_S698PM
|
||||
comment "S698PM Configuration Options"
|
||||
|
||||
menu "S698PM Peripheral Support"
|
||||
|
||||
config S698PM_WDG
|
||||
bool "Watchdog timer (WDT)"
|
||||
default n
|
||||
select WATCHDOG
|
||||
|
||||
config S698PM_TIM1
|
||||
bool "Timer 1 (T1)"
|
||||
default n
|
||||
|
||||
config S698PM_TIM2
|
||||
bool "Timer 2 (T2)"
|
||||
default n
|
||||
|
||||
config S698PM_TIM3
|
||||
bool "Timer 3 (T3)"
|
||||
default n
|
||||
|
||||
config S698PM_TIM4
|
||||
bool "Timer 4 (T4)"
|
||||
default n
|
||||
|
||||
config S698PM_UART1
|
||||
bool "UART1"
|
||||
default n
|
||||
select UART1_SERIALDRIVER
|
||||
select ARCH_HAVE_SERIAL_TERMIOS
|
||||
|
||||
config S698PM_UART2
|
||||
bool "UART2"
|
||||
default n
|
||||
select UART2_SERIALDRIVER
|
||||
select ARCH_HAVE_SERIAL_TERMIOS
|
||||
|
||||
config S698PM_UART3
|
||||
bool "UART3"
|
||||
default n
|
||||
select UART3_SERIALDRIVER
|
||||
select ARCH_HAVE_SERIAL_TERMIOS
|
||||
|
||||
config S698PM_UART4
|
||||
bool "UART4"
|
||||
default n
|
||||
select UART4_SERIALDRIVER
|
||||
select ARCH_HAVE_SERIAL_TERMIOS
|
||||
|
||||
endmenu # S698PM Peripheral Selections
|
||||
|
||||
menuconfig S698PM_GPIOIRQ
|
||||
bool "GPIO Interrupt Support"
|
||||
default n
|
||||
---help---
|
||||
Build in support for interrupts based on GPIO inputs from IOPorts
|
||||
|
||||
if S698PM_GPIOIRQ
|
||||
|
||||
config S698PM_GPIOIRQ_PORT4
|
||||
bool "I/O PORT4 Interrupt Support"
|
||||
default n
|
||||
|
||||
config S698PM_GPIOIRQ_PORT5
|
||||
bool "I/O PORT5 Interrupt Support"
|
||||
default n
|
||||
|
||||
config S698PM_GPIOIRQ_PORT6
|
||||
bool "I/O PORT6 Interrupt Support"
|
||||
default n
|
||||
config S698PM_GPIOIRQ_PORT7
|
||||
bool "I/O PORT7 Interrupt Support"
|
||||
default n
|
||||
|
||||
endif # S698PM_GPIOIRQ
|
||||
|
||||
menu "Timer Configuration"
|
||||
|
||||
if SCHED_TICKLESS
|
||||
|
||||
config S698PM_ONESHOT
|
||||
bool
|
||||
default y
|
||||
|
||||
config S698PM_FREERUN
|
||||
bool
|
||||
default y
|
||||
|
||||
config S698PM_TICKLESS_ONESHOT
|
||||
int "Tickless one-shot timer channel"
|
||||
default 1
|
||||
range 1 2
|
||||
depends on S698PM_ONESHOT
|
||||
---help---
|
||||
If the Tickless OS feature is enabled, then one clock must be
|
||||
assigned to provide the one-shot timer needed by the OS.
|
||||
|
||||
config S698PM_TICKLESS_FREERUN
|
||||
int "Tickless free-running timer channel"
|
||||
default 2
|
||||
range 1 2
|
||||
depends on S698PM_FREERUN
|
||||
---help---
|
||||
If the Tickless OS feature is enabled, then one clock must be
|
||||
assigned to provide the free-running timer needed by the OS.
|
||||
|
||||
endif # SCHED_TICKLESS
|
||||
|
||||
if !SCHED_TICKLESS
|
||||
|
||||
config S698PM_ONESHOT
|
||||
bool "TIM one-shot wrapper"
|
||||
default n
|
||||
---help---
|
||||
Enable a wrapper around the low level timer/counter functions to
|
||||
support one-shot timer.
|
||||
|
||||
config S698PM_FREERUN
|
||||
bool "TIM free-running wrapper"
|
||||
default n
|
||||
---help---
|
||||
Enable a wrapper around the low level timer/counter functions to
|
||||
support a free-running timer.
|
||||
|
||||
endif # !SCHED_TICKLESS
|
||||
|
||||
endmenu # Timer Configuration
|
||||
|
||||
endif
|
||||
58
arch/sparc/src/s698pm/Make.defs
Normal file
58
arch/sparc/src/s698pm/Make.defs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
############################################################################
|
||||
# arch/sparc/src/s698pm/Make.defs
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include common/Make.defs
|
||||
|
||||
# The start-up, "head", file
|
||||
|
||||
HEAD_ASRC = s698pm_head.S
|
||||
|
||||
# Required S698PM files
|
||||
|
||||
CHIP_ASRCS = s698pm_exceptions.S
|
||||
CHIP_CSRCS = s698pm-lowconsole.c s698pm-lowinit.c s698pm-serial.c s698pm-irq.c s698pm_tim.c
|
||||
|
||||
ifeq ($(CONFIG_TIMER),y)
|
||||
CHIP_CSRCS += s698pm_tim_lowerhalf.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_S698PM_WDG),y)
|
||||
CHIP_CSRCS += s698pm_wdg.c
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
CHIP_CSRCS += s698pm-timerisr.c
|
||||
else
|
||||
CHIP_CSRCS += s698pm_tickless.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_S698PM_ONESHOT),y)
|
||||
CHIP_CSRCS += s698pm_oneshot.c s698pm_oneshot_lowerhalf.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_S698PM_FREERUN),y)
|
||||
CHIP_CSRCS += s698pm_freerun.c
|
||||
endif
|
||||
|
||||
# Configuration-dependent files
|
||||
|
||||
ifeq ($(CONFIG_SMP),y)
|
||||
CHIP_CSRCS += s698pm_cpuindex.c s698pm_cpustart.c s698pm_cpupause.c s698pm_cpuidlestack.c
|
||||
endif
|
||||
37
arch/sparc/src/s698pm/chip.h
Normal file
37
arch/sparc/src/s698pm/chip.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/chip.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_SPARC_SRC_S698PM_CHIP_H
|
||||
#define __ARCH_SPARC_SRC_S698PM_CHIP_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/* Include only the memory map. Other chip hardware files should then
|
||||
* include this file for the proper setup
|
||||
*/
|
||||
|
||||
#include "s698pm-memorymap.h"
|
||||
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_CHIP_H */
|
||||
|
||||
100
arch/sparc/src/s698pm/s698pm-config.h
Normal file
100
arch/sparc/src/s698pm/s698pm-config.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-config.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_SPARC_SRC_S698PM_CONFIG_H
|
||||
#define __ARCH_SPARC_SRC_S698PM_CONFIG_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
#include "s698pm-memorymap.h"
|
||||
#include "s698pm-uart.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* UARTs ********************************************************************/
|
||||
|
||||
/* Don't enable UARTs not supported by the chip. */
|
||||
|
||||
#if CHIP_NUARTS < 1
|
||||
# undef CONFIG_S698PM_UART1
|
||||
# undef CONFIG_S698PM_UART2
|
||||
# undef CONFIG_S698PM_UART3
|
||||
# undef CONFIG_S698PM_UART4
|
||||
#elif CHIP_NUARTS < 2
|
||||
# undef CONFIG_S698PM_UART2
|
||||
# undef CONFIG_S698PM_UART3
|
||||
# undef CONFIG_S698PM_UART4
|
||||
#elif CHIP_NUARTS < 3
|
||||
# undef CONFIG_S698PM_UART3
|
||||
# undef CONFIG_S698PM_UART4
|
||||
#elif CHIP_NUARTS < 4
|
||||
# undef CONFIG_S698PM_UART4
|
||||
#endif
|
||||
|
||||
/* Are any UARTs enabled? */
|
||||
|
||||
#undef HAVE_UART_DEVICE
|
||||
#if defined(CONFIG_S698PM_UART1) || defined(CONFIG_S698PM_UART2) || \
|
||||
defined(CONFIG_S698PM_UART3) || defined(CONFIG_S698PM_UART4)
|
||||
# define HAVE_UART_DEVICE 1
|
||||
#endif
|
||||
|
||||
/* Is there a serial console? There should be no more than one defined. It
|
||||
* could be on any UARTn, n=1,.. CHIP_NUARTS
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_S698PM_UART1)
|
||||
# undef CONFIG_UART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART3_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART4_SERIAL_CONSOLE
|
||||
# define HAVE_SERIAL_CONSOLE 1
|
||||
#elif defined(CONFIG_UART2_SERIAL_CONSOLE) && defined(CONFIG_S698PM_UART2)
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART3_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART4_SERIAL_CONSOLE
|
||||
# define HAVE_SERIAL_CONSOLE 1
|
||||
#elif defined(CONFIG_UART3_SERIAL_CONSOLE) && defined(CONFIG_S698PM_UART3)
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART4_SERIAL_CONSOLE
|
||||
# define HAVE_SERIAL_CONSOLE 1
|
||||
#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_S698PM_UART4)
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART3_SERIAL_CONSOLE
|
||||
# define HAVE_SERIAL_CONSOLE 1
|
||||
#else
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART3_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART4_SERIAL_CONSOLE
|
||||
# undef HAVE_SERIAL_CONSOLE
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_CONFIG_H */
|
||||
541
arch/sparc/src/s698pm/s698pm-irq.c
Normal file
541
arch/sparc/src/s698pm/s698pm-irq.c
Normal file
|
|
@ -0,0 +1,541 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-irq.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 <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
#include "s698pm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||
|
||||
#if defined(CONFIG_SMP)
|
||||
# define INTSTACK_ALLOC (CONFIG_SMP_NCPUS * INTSTACK_SIZE)
|
||||
#else
|
||||
# define INTSTACK_ALLOC (INTSTACK_SIZE)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* IRQ to CPU and CPU interrupts mapping:
|
||||
*
|
||||
* Encoding: CCCIIIII
|
||||
* C: CPU that enabled the interrupt (0 ~ 3).
|
||||
* I: Associated CPU interrupt (0 ~ 31).
|
||||
*/
|
||||
|
||||
#define IRQ_UNMAPPED 0xff
|
||||
#define IRQ_GETCPU(m) (((m) & 0xe0) >> 0x05)
|
||||
#define IRQ_GETCPUINT(m) ((m) & 0x1f)
|
||||
#define IRQ_MKMAP(c, i) (((c) << 0x05) | (i))
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
static volatile uint8_t g_irqmap[NR_IRQS];
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||
/* In the SMP configuration, we will need custom interrupt stacks.
|
||||
* These definitions provide the aligned stack allocations.
|
||||
*/
|
||||
|
||||
static uint64_t g_intstack_alloc[INTSTACK_ALLOC >> 3];
|
||||
|
||||
/* These definitions provide the "top" of the push-down stacks. */
|
||||
|
||||
uintptr_t g_cpu_intstack_top[CONFIG_SMP_NCPUS] =
|
||||
{
|
||||
(uintptr_t)g_intstack_alloc + INTSTACK_SIZE,
|
||||
#if defined(CONFIG_SMP)
|
||||
|
||||
#if CONFIG_SMP_NCPUS > 1
|
||||
(uintptr_t)g_intstack_alloc + (2 * INTSTACK_SIZE),
|
||||
#if CONFIG_SMP_NCPUS > 2
|
||||
(uintptr_t)g_intstack_alloc + (3 * INTSTACK_SIZE),
|
||||
#if CONFIG_SMP_NCPUS > 3
|
||||
(uintptr_t)g_intstack_alloc + (4 * INTSTACK_SIZE),
|
||||
#endif /* CONFIG_SMP_NCPUS > 3 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 2 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 1 */
|
||||
|
||||
#endif /* defined(CONFIG_SMP) */
|
||||
};
|
||||
#endif /* if CONFIG_ARCH_INTERRUPTSTACK > 7 */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_ARCH_IRQPRIO
|
||||
static int up_prioritize_irq(int irq, int priority);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_irqinitialize
|
||||
****************************************************************************/
|
||||
|
||||
void up_irqinitialize(void)
|
||||
{
|
||||
int irq = 0;
|
||||
|
||||
for (irq = 0; irq < NR_IRQS; irq++)
|
||||
{
|
||||
g_irqmap[irq] = IRQ_UNMAPPED;
|
||||
}
|
||||
|
||||
/* Initialize CPU interrupts */
|
||||
|
||||
s698pm_cpuint_initialize();
|
||||
|
||||
/* Set interrupts priority */
|
||||
|
||||
for (irq = S698PM_IRQ_FIRST_INT; irq <= S698PM_IRQ_LAST_INT; irq++)
|
||||
{
|
||||
/* Set all interrupts to the default (low) priority */
|
||||
|
||||
(void)up_prioritize_irq(irq, 0);
|
||||
}
|
||||
|
||||
/* Attach software interrupts */
|
||||
|
||||
irq_attach(S698PM_IRQ_SW_SYSCALL_TA0, up_swint0, NULL);
|
||||
irq_attach(S698PM_IRQ_SW_SYSCALL_TA8, up_swint1, NULL);
|
||||
|
||||
/* And finally, enable cpu interrupts */
|
||||
|
||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||
up_irq_enable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_cpuint_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize CPU interrupts
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; A negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_cpuint_initialize(void)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
int cpu = 0;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Which CPU are we initializing */
|
||||
|
||||
cpu = up_cpu_index();
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
#endif
|
||||
|
||||
/* get Interrupt_Mask reg address of cpu */
|
||||
|
||||
regaddr = S698PM_IRQREG_P0_MASK + 4 * cpu;
|
||||
|
||||
/* Disable all CPU interrupts on this CPU */
|
||||
|
||||
putreg32(0, regaddr);
|
||||
|
||||
#if defined CONFIG_SMP
|
||||
/* Attach IPI interrupts */
|
||||
|
||||
irq_attach(S698PM_IPI_IRQ, s698pm_pause_handler, NULL);
|
||||
|
||||
(void)s698pm_setup_irq(cpu, S698PM_IPI_IRQ, 0);
|
||||
|
||||
/* And enable the IPI interrupt */
|
||||
|
||||
up_enable_irq(S698PM_IPI_IRQ);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_setup_irq
|
||||
*
|
||||
* Description:
|
||||
* This function sets up the IRQ. It allocates a CPU interrupt of the given
|
||||
* priority andattaches it to the given irq.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The CPU to receive the interrupt 0~3
|
||||
* irq - The irq number from irq.h to be assigned to a EXT interrupt.
|
||||
* priority - Interrupt's priority (0~1).
|
||||
*
|
||||
* Returned Value:
|
||||
* The allocated CPU interrupt on success, a negated errno value on
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_setup_irq(int cpu, int irq, int priority)
|
||||
{
|
||||
irqstate_t irqstate;
|
||||
int cpuint;
|
||||
|
||||
irqstate = enter_critical_section();
|
||||
|
||||
if (irq >= S698PM_IRQ_FIRST_INT && irq <= S698PM_IRQ_LAST_INT)
|
||||
{
|
||||
cpuint = irq - S698PM_IRQ_FIRST_INT + 1;
|
||||
}
|
||||
else if (irq > S698PM_IRQ_LAST && irq < NR_IRQS)
|
||||
{
|
||||
/* Second level interrupt share a IRQ and connnect to a interrupt 14
|
||||
* of first level interrupt(that is IRQ 0x1E), We extend Second level
|
||||
* interrupt to IRQ 0x100~0x10F. because first level interrupt in the
|
||||
* interrupt reister is bit 0~15 and second level interrupt is bit 16
|
||||
* ~31, so cpuint of second level interrupt is irq - 256 +
|
||||
* S698PM_EXTENDED_START
|
||||
*/
|
||||
|
||||
cpuint = irq - 256 + S698PM_EXTENDED_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuint = -1;
|
||||
}
|
||||
|
||||
DEBUGASSERT(cpuint >= 0 && cpuint < S698PM_CPUINT_MAX);
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
g_irqmap[irq] = IRQ_MKMAP(cpu, cpuint);
|
||||
(void)up_prioritize_irq(irq, priority);
|
||||
|
||||
leave_critical_section(irqstate);
|
||||
|
||||
return cpuint;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_teardown_irq
|
||||
*
|
||||
* Description:
|
||||
* This function undoes the operations done by s698pm_setup_irq.
|
||||
* It detaches a ext interrupt from a CPU irq.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The irq number from irq.h to be assigned to a EXT interrupt.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void s698pm_teardown_irq(int irq)
|
||||
{
|
||||
irqstate_t irqstate;
|
||||
|
||||
irqstate = enter_critical_section();
|
||||
|
||||
g_irqmap[irq] = IRQ_UNMAPPED;
|
||||
|
||||
leave_critical_section(irqstate);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_disable_irq
|
||||
*
|
||||
* Description:
|
||||
* Disable the IRQ specified by 'irq'
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_disable_irq(int irq)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
int cpu = IRQ_GETCPU(g_irqmap[irq]);
|
||||
int cpuint = IRQ_GETCPUINT(g_irqmap[irq]);
|
||||
|
||||
if (g_irqmap[irq] == IRQ_UNMAPPED)
|
||||
{
|
||||
/* This interrupt is already disabled. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGASSERT(cpuint >= 0 && cpuint < S698PM_CPUINT_MAX);
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
if ((irq >= S698PM_IRQ_FIRST_INT && irq <= S698PM_IRQ_LAST_INT) ||
|
||||
(irq > S698PM_IRQ_LAST && irq < NR_IRQS))
|
||||
{
|
||||
/* get Interrupt_Mask reg address of cpu */
|
||||
|
||||
regaddr = S698PM_IRQREG_P0_MASK + 4 * cpu;
|
||||
|
||||
/* Disable the interrupt by clearing the associated bit in the
|
||||
* Interrupt_Mask
|
||||
*/
|
||||
|
||||
modifyreg32(regaddr, 1 << cpuint, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_enable_irq
|
||||
*
|
||||
* Description:
|
||||
* Enable the IRQ specified by 'irq'
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_enable_irq(int irq)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
int cpu = IRQ_GETCPU(g_irqmap[irq]);
|
||||
int cpuint = IRQ_GETCPUINT(g_irqmap[irq]);
|
||||
|
||||
if (g_irqmap[irq] == IRQ_UNMAPPED)
|
||||
{
|
||||
/* This interrupt is already disabled. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGASSERT(cpuint >= 0 && cpuint < S698PM_CPUINT_MAX);
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
if ((irq >= S698PM_IRQ_FIRST_INT && irq <= S698PM_IRQ_LAST_INT) ||
|
||||
(irq > S698PM_IRQ_LAST && irq < NR_IRQS))
|
||||
{
|
||||
/* get Interrupt_Mask reg address of cpu */
|
||||
|
||||
regaddr = S698PM_IRQREG_P0_MASK + 4 * cpu;
|
||||
|
||||
/* Disable the interrupt by clearing the associated bit in the
|
||||
* Interrupt_Mask
|
||||
*/
|
||||
|
||||
modifyreg32(regaddr, 1 << cpuint, 1 << cpuint);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_pending_irq
|
||||
*
|
||||
* Description:
|
||||
* Return true if the interrupt is pending and unmasked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool up_pending_irq(int irq)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
uint16_t regval;
|
||||
uint16_t regval1;
|
||||
uint16_t regval2;
|
||||
int cpu = IRQ_GETCPU(g_irqmap[irq]);
|
||||
int cpuint = IRQ_GETCPUINT(g_irqmap[irq]);
|
||||
|
||||
/* Test if the interrupt is pending by reading both the MASK and ACK
|
||||
* register. Return true if the bit associated with the irq is both
|
||||
* pending the ACK and enabled in the MASK.
|
||||
*/
|
||||
|
||||
if (g_irqmap[irq] == IRQ_UNMAPPED)
|
||||
{
|
||||
/* This interrupt is already disabled. */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUGASSERT(cpuint >= 0 && cpuint < S698PM_CPUINT_MAX);
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
|
||||
|
||||
if ((irq >= S698PM_IRQ_FIRST_INT && irq <= S698PM_IRQ_LAST_INT) ||
|
||||
(irq > S698PM_IRQ_LAST && irq < NR_IRQS))
|
||||
{
|
||||
/* get interrupt mask register address of cpu */
|
||||
|
||||
regaddr = S698PM_IRQREG_P0_MASK + 4 * cpu;
|
||||
regval1 = getreg32(regaddr);
|
||||
|
||||
/* get interrupt pend register address of cpu */
|
||||
|
||||
regaddr = S698PM_IRQREG_IPEND;
|
||||
regval2 = getreg32(regaddr);
|
||||
|
||||
/* Get the set of unmasked, pending interrupts. */
|
||||
|
||||
regval = regval1 & regval2;
|
||||
|
||||
/* Return true if the interrupt is pending and unmask. */
|
||||
|
||||
return (regval & (1 << cpuint)) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_clrpend_irq
|
||||
*
|
||||
* Description:
|
||||
* Clear any pending interrupt
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_clrpend_irq(int irq)
|
||||
{
|
||||
int cpuint = IRQ_GETCPUINT(g_irqmap[irq]);
|
||||
|
||||
/* Test if the interrupt is pending by reading both the MASK and ACK
|
||||
* register. Return true if the bit associated with the irq is both
|
||||
* pending the ACK and enabled in the MASK.
|
||||
*/
|
||||
|
||||
if (g_irqmap[irq] == IRQ_UNMAPPED)
|
||||
{
|
||||
/* This interrupt is already disabled. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGASSERT(cpuint >= 0 && cpuint < S698PM_CPUINT_MAX);
|
||||
|
||||
/* Acknowledge the interrupt by clearing the associated bit in the ITP
|
||||
* register. It is necessary to do this BEFORE lowering the interrupt
|
||||
* priority level otherwise recursive interrupts would occur.
|
||||
*/
|
||||
|
||||
if ((irq >= S698PM_IRQ_FIRST_INT && irq <= S698PM_IRQ_LAST_INT) ||
|
||||
(irq > S698PM_IRQ_LAST && irq < NR_IRQS))
|
||||
{
|
||||
/* written with a ‘1’, in Interrupt Clear Register
|
||||
* will clear the corresponding bit(s) in the interrupt pending
|
||||
* register
|
||||
*/
|
||||
|
||||
putreg32(1 << cpuint, S698PM_IRQREG_ICLEAR);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_prioritize_irq
|
||||
*
|
||||
* Description:
|
||||
* It is possible to change the priority level of an interrupt using the two
|
||||
* priority levels from the interrupt mask and priority register (ITMP).
|
||||
* Each interrupt can be assigned to one of two levels as programmed in the
|
||||
* Interrupt mask and priority register. Level 1 has higher priority than
|
||||
* level 0. Within each level the interrupts are prioritised
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_ARCH_IRQPRIO
|
||||
static
|
||||
#endif
|
||||
int up_prioritize_irq(int irq, int priority)
|
||||
{
|
||||
int shift;
|
||||
|
||||
/* Don't allow this function to be used for disabling interrupts. */
|
||||
|
||||
DEBUGASSERT((unsigned)irq < NR_IRQS && (unsigned)(priority) < 2);
|
||||
|
||||
if (irq >= S698PM_IRQ_FIRST_INT && irq <= S698PM_IRQ_LAST_INT)
|
||||
{
|
||||
shift = irq - S698PM_IRQ_FIRST_INT + 1;
|
||||
|
||||
/* Set the new interrupt priority */
|
||||
|
||||
putreg32(1 << shift, S698PM_IRQREG_ILEVEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Value out of range.. just ignore */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sparc_intstack_top
|
||||
*
|
||||
* Description:
|
||||
* Return a pointer to the top the correct interrupt stack allocation
|
||||
* for the current CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||
uintptr_t up_intstack_top(void)
|
||||
{
|
||||
#if defined(CONFIG_SMP)
|
||||
return g_cpu_intstack_top[up_cpu_index()];
|
||||
#else
|
||||
return g_cpu_intstack_top[0];
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sparc_intstack_alloc
|
||||
*
|
||||
* Description:
|
||||
* Return a pointer to the "alloc" the correct interrupt stack allocation
|
||||
* for the current CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||
uintptr_t up_intstack_alloc(void)
|
||||
{
|
||||
#if defined(CONFIG_SMP)
|
||||
return g_cpu_intstack_top[up_cpu_index()] - INTSTACK_SIZE;
|
||||
#else
|
||||
return g_cpu_intstack_top[0] - INTSTACK_SIZE;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
266
arch/sparc/src/s698pm/s698pm-lowconsole.c
Normal file
266
arch/sparc/src/s698pm/s698pm-lowconsole.c
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-lowconsole.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 <arch/board/board.h>
|
||||
|
||||
#include "s698pm-config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
#include "s698pm-uart.h"
|
||||
#include "s698pm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Select UART parameters for the selected console */
|
||||
|
||||
#ifdef HAVE_SERIAL_CONSOLE
|
||||
# if defined(CONFIG_UART1_SERIAL_CONSOLE)
|
||||
# define S698PM_CONSOLE_BASE S698PM_UART1_BASE
|
||||
# define S698PM_CONSOLE_BAUD CONFIG_UART1_BAUD
|
||||
# define S698PM_CONSOLE_BITS CONFIG_UART1_BITS
|
||||
# define S698PM_CONSOLE_PARITY CONFIG_UART1_PARITY
|
||||
# define S698PM_CONSOLE_2STOP CONFIG_UART1_2STOP
|
||||
# elif defined(CONFIG_UART2_SERIAL_CONSOLE)
|
||||
# define S698PM_CONSOLE_BASE S698PM_UART2_BASE
|
||||
# define S698PM_CONSOLE_BAUD CONFIG_UART2_BAUD
|
||||
# define S698PM_CONSOLE_BITS CONFIG_UART2_BITS
|
||||
# define S698PM_CONSOLE_PARITY CONFIG_UART2_PARITY
|
||||
# define S698PM_CONSOLE_2STOP CONFIG_UART2_2STOP
|
||||
# elif defined(CONFIG_UART3_SERIAL_CONSOLE)
|
||||
# define S698PM_CONSOLE_BASE S698PM_UART3_BASE
|
||||
# define S698PM_CONSOLE_BAUD CONFIG_UART3_BAUD
|
||||
# define S698PM_CONSOLE_BITS CONFIG_UART3_BITS
|
||||
# define S698PM_CONSOLE_PARITY CONFIG_UART3_PARITY
|
||||
# define S698PM_CONSOLE_2STOP CONFIG_UART3_2STOP
|
||||
# elif defined(CONFIG_UART4_SERIAL_CONSOLE)
|
||||
# define S698PM_CONSOLE_BASE S698PM_UART4_BASE
|
||||
# define S698PM_CONSOLE_BAUD CONFIG_UART4_BAUD
|
||||
# define S698PM_CONSOLE_BITS CONFIG_UART4_BITS
|
||||
# define S698PM_CONSOLE_PARITY CONFIG_UART4_PARITY
|
||||
# define S698PM_CONSOLE_2STOP CONFIG_UART4_2STOP
|
||||
# else
|
||||
# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_putreg
|
||||
*
|
||||
* Description:
|
||||
* Write a value to a UART register
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
static inline void s698pm_putreg(uintptr_t uart_base, unsigned int offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, uart_base + offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_getreg
|
||||
*
|
||||
* Description:
|
||||
* Get a value from a UART register
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
static inline uint32_t s698pm_getreg(uintptr_t uart_base,
|
||||
unsigned int offset)
|
||||
{
|
||||
return getreg32(uart_base + offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_uartreset
|
||||
*
|
||||
* Description:
|
||||
* Reset UART.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
void s698pm_uartreset(uintptr_t uart_base)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* Clear USART configuration */
|
||||
|
||||
reg = s698pm_getreg(uart_base, S698PM_UART_CTRLREG_OFFSET);
|
||||
uart_disable(reg);
|
||||
uart_parity_config(reg, NONE);
|
||||
uart_flow_ctrl_config(reg, OFF);
|
||||
uart_loopback_config(reg, OFF);
|
||||
s698pm_putreg(uart_base, S698PM_UART_CTRLREG_OFFSET, reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_uartconfigure
|
||||
*
|
||||
* Description:
|
||||
* Configure a UART as a console.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
void s698pm_uartconfigure(uintptr_t uart_base, uint32_t baudrate,
|
||||
unsigned int parity, unsigned int nbits,
|
||||
bool stop2)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* Select baud. */
|
||||
|
||||
s698pm_putreg(S698PM_CONSOLE_BASE, S698PM_UART_SCALREG_OFFSET,
|
||||
uart_set_baudrate(baudrate));
|
||||
|
||||
reg = s698pm_getreg(S698PM_CONSOLE_BASE, S698PM_UART_CTRLREG_OFFSET);
|
||||
|
||||
/* Select parity */
|
||||
|
||||
if (parity == 1)
|
||||
{
|
||||
uart_parity_config(reg, ODD); /* Odd parity */
|
||||
}
|
||||
else if (parity == 2)
|
||||
{
|
||||
uart_parity_config(reg, EVEN); /* Even parity */
|
||||
}
|
||||
else
|
||||
{
|
||||
uart_parity_config(reg, NONE); /* Even none */
|
||||
}
|
||||
|
||||
uart_flow_ctrl_config(reg, OFF);
|
||||
uart_loopback_config(reg, OFF);
|
||||
|
||||
uart_enable(reg);
|
||||
|
||||
s698pm_putreg(S698PM_CONSOLE_BASE, S698PM_UART_CTRLREG_OFFSET, reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_consoleinit
|
||||
*
|
||||
* Description:
|
||||
* Initialize a console for debug output. This function is called very
|
||||
* early in the initialization sequence to configure the serial console
|
||||
* uart
|
||||
* (only).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void s698pm_consoleinit(void)
|
||||
{
|
||||
uint32_t gpreg;
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
|
||||
/* Setup up pin selection registers for all configured UARTs. The board.h
|
||||
* header file must provide these definitions to select the correct pin
|
||||
* configuration for each enabled UARt.
|
||||
*/
|
||||
|
||||
gpreg = getreg32(S698PM_GPREG_BASE);
|
||||
|
||||
#ifdef CONFIG_S698PM_UART3
|
||||
/* Configure UART3 RX (input) and TX (output) pins */
|
||||
|
||||
gpreg |= 0x1;
|
||||
putreg32(gpreg, S698PM_GPREG_BASE);
|
||||
|
||||
#endif /* CONFIG_S698PM_UART3 */
|
||||
|
||||
#ifdef CONFIG_S698PM_UART4
|
||||
/* Configure UART4 RX (input) and TX (output) pins */
|
||||
|
||||
gpreg |= 0x2;
|
||||
putreg32(gpreg, S698PM_GPREG_BASE);
|
||||
|
||||
#endif /* CONFIG_S698PM_UART4 */
|
||||
|
||||
#ifdef HAVE_SERIAL_CONSOLE
|
||||
/* Configure the console uart */
|
||||
|
||||
s698pm_uartconfigure(S698PM_CONSOLE_BASE, S698PM_CONSOLE_BAUD,
|
||||
S698PM_CONSOLE_PARITY, S698PM_CONSOLE_BITS,
|
||||
S698PM_CONSOLE_2STOP);
|
||||
|
||||
#endif /* HAVE_SERIAL_CONSOLE */
|
||||
#endif /* HAVE_UART_DEVICE */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_lowputc
|
||||
*
|
||||
* Description:
|
||||
* Output one byte on the serial console
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_lowputc(char ch)
|
||||
{
|
||||
#ifdef HAVE_SERIAL_CONSOLE
|
||||
while ((s698pm_getreg(S698PM_CONSOLE_BASE, S698PM_UART_STATREG_OFFSET) &
|
||||
UART_STA_TE) == 0);
|
||||
|
||||
/* Then write the character to the TX data register */
|
||||
|
||||
s698pm_putreg(S698PM_CONSOLE_BASE, S698PM_UART_TXREG_OFFSET,
|
||||
(uint32_t)ch);
|
||||
#endif
|
||||
}
|
||||
119
arch/sparc/src/s698pm/s698pm-lowinit.c
Normal file
119
arch/sparc/src/s698pm/s698pm-lowinit.c
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-lowinit.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 "s698pm-config.h"
|
||||
#include "up_internal.h"
|
||||
#include "s698pm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: showprogress
|
||||
*
|
||||
* Description:
|
||||
* Print a character on the UART to show boot status.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG_FEATURES
|
||||
# define showprogress(c) up_lowputc(c)
|
||||
#else
|
||||
# define showprogress(c)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_lowinit
|
||||
*
|
||||
* Description:
|
||||
* This performs basic initialization of the USART used for the serial
|
||||
* console. Its purpose is to get the console output available as soon
|
||||
* as possible.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_lowinit(void)
|
||||
{
|
||||
uint32_t *dest;
|
||||
|
||||
/* Initialize a console (probably a serial console) */
|
||||
|
||||
s698pm_consoleinit();
|
||||
|
||||
showprogress('A');
|
||||
|
||||
/* Clear .bss. We'll do this inline (vs. calling memset) just to be
|
||||
* certain that there are no issues with the state of global variables.
|
||||
*/
|
||||
|
||||
for (dest = &_bss_start; dest < &_end; )
|
||||
{
|
||||
*dest++ = 0;
|
||||
}
|
||||
|
||||
showprogress('B');
|
||||
/* Perform early serial initialization (so that we will have debug output
|
||||
* available as soon as possible).
|
||||
*/
|
||||
|
||||
#ifdef USE_EARLYSERIALINIT
|
||||
up_earlyserialinit();
|
||||
#endif
|
||||
|
||||
/* Perform board-level initialization */
|
||||
|
||||
s698pm_boardinitialize();
|
||||
|
||||
/* Then start NuttX */
|
||||
|
||||
showprogress('\r');
|
||||
showprogress('\n');
|
||||
}
|
||||
57
arch/sparc/src/s698pm/s698pm-memorymap.h
Normal file
57
arch/sparc/src/s698pm/s698pm-memorymap.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-memorymap.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_SPARC_SRC_S698PM_S698PM_MEMORYMAP_H
|
||||
#define __ARCH_SPARC_SRC_S698PM_S698PM_MEMORYMAP_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register Base Addresses **************************************************/
|
||||
|
||||
/* UART 1-4 Register Base Addresses */
|
||||
|
||||
# define S698PM_UART1_BASE (0x80000100)
|
||||
# define S698PM_UART2_BASE (0x80000900)
|
||||
# define S698PM_UART3_BASE (0x80100100)
|
||||
# define S698PM_UART4_BASE (0x80100200)
|
||||
|
||||
/* GPIO metux Register Base Addresses */
|
||||
|
||||
# define S698PM_GPREG_BASE (0x80100500)
|
||||
|
||||
#define S698PM_DSU_BASE (0x90000000)
|
||||
#define S698PM_DSU_CPU0_BASE (0x90000000)
|
||||
#define S698PM_DSU_CPU1_BASE (0x91000000)
|
||||
#define S698PM_DSU_CPU2_BASE (0x92000000)
|
||||
#define S698PM_DSU_CPU3_BASE (0x93000000)
|
||||
|
||||
#define S698PM_DSU_PC_OFFSET 0x400010 /* PC register */
|
||||
#define S698PM_DSU_NPC_OFFSET 0x400014 /* nPC register */
|
||||
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_S698PM_MEMORYMAP_H */
|
||||
|
||||
1031
arch/sparc/src/s698pm/s698pm-serial.c
Normal file
1031
arch/sparc/src/s698pm/s698pm-serial.c
Normal file
File diff suppressed because it is too large
Load diff
156
arch/sparc/src/s698pm/s698pm-timerisr.c
Normal file
156
arch/sparc/src/s698pm/s698pm-timerisr.c
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-timerisr.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 <debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
#include "s698pm.h"
|
||||
#include "s698pm_tim.h"
|
||||
#include "s698pm_irq.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The CPU frequency is given by BOARD_CPU_CLOCK (defined in board.h). The
|
||||
* desired interrupt frequency is given by CONFIG_USEC_PER_TICK. An unscaled
|
||||
* ideal match is given by:
|
||||
*
|
||||
* CLOCK = CPU_CLOCK / DIVISOR # CPU clocks/sec
|
||||
* MATCH = CLOCK / CLOCKS_PER_SEC # CPU clocks/timer tick
|
||||
* MATCH = CPU_CLOCK / DIVISOR / CLOCKS_PER_SEC # CPU clocks/timer tick
|
||||
*
|
||||
* But we only have 16-bits of accuracy so we need to pick the smallest
|
||||
* divisor using the following brute force calculation:
|
||||
*/
|
||||
|
||||
#define S698PM_TIMER_CLOCK 1000000
|
||||
#define MATCH1 (( 1000000 / CLOCKS_PER_SEC) - 1)
|
||||
|
||||
/* Bit 0: enables the timer when set */
|
||||
|
||||
#define TIMCTR_ENABLE_COUNTER (1 << 0)
|
||||
|
||||
/* Bit 1: automatically reloaded with the reload value after each underflow */
|
||||
|
||||
#define TIMCTR_AUTO_RELOAD (1 << 1)
|
||||
|
||||
/* Bit 2: Set 1, will load the timer reload register into the timer counter
|
||||
* register
|
||||
*/
|
||||
|
||||
#define TIMCTR_LOAD_COUNTER (1 << 2)
|
||||
|
||||
/* Bit 3: Set 1, will triger underflow interrupt each underflow */
|
||||
|
||||
#define TIMCTR_ENABLE_INT (1 << 3)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Function: s698pm_timerisr
|
||||
*
|
||||
* Description:
|
||||
* The timer ISR will perform a variety of services for various portions
|
||||
* of the systems.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_timerisr(int irq, uint32_t *regs, void *arg)
|
||||
{
|
||||
/* Clear the pending timer interrupt */
|
||||
|
||||
up_clrpend_irq(S698PM_IRQ_TIMER1);
|
||||
|
||||
/* Process timer interrupt */
|
||||
|
||||
nxsched_process_timer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Function: up_timer_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function is called during start-up to initialize the timer
|
||||
* interrupt. NOTE: This function depends on setup of OSC32 by
|
||||
* up_clkinitialize().
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_timer_initialize(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
regval = (BOARD_CPU_CLOCK / S698PM_TIMER_CLOCK) - 1;
|
||||
|
||||
putreg16(regval, S698PM_TIMPRE_BASE + S698PM_TIM_PSCLOAD_OFFSET);
|
||||
|
||||
putreg16(regval, S698PM_TIMPRE_BASE + S698PM_TIM_PSCCONT_OFFSET);
|
||||
|
||||
/* Setup timer 1 compare match A to generate a tick interrupt.
|
||||
*
|
||||
* First, setup the match value for compare match A.
|
||||
*/
|
||||
|
||||
putreg32(MATCH1, S698PM_TIM1_BASE + S698PM_TIM_CNT_OFFSET);
|
||||
putreg32(MATCH1, S698PM_TIM1_BASE + S698PM_TIM_ARR_OFFSET);
|
||||
|
||||
regval = (TIMCTR_ENABLE_COUNTER | TIMCTR_AUTO_RELOAD |
|
||||
TIMCTR_LOAD_COUNTER | TIMCTR_ENABLE_INT);
|
||||
putreg32(regval, S698PM_TIM1_BASE + S698PM_TIM_CR_OFFSET);
|
||||
|
||||
/* Configure the timer interrupt */
|
||||
|
||||
up_clrpend_irq(S698PM_IRQ_TIMER1);
|
||||
|
||||
/* Attach the timer interrupt vector */
|
||||
|
||||
irq_attach(S698PM_IRQ_TIMER1, (xcpt_t)s698pm_timerisr, NULL);
|
||||
|
||||
/* Set up to timer1 interrupts on the current CPU */
|
||||
|
||||
#ifdef CONFIG_ARCH_IRQPRIO
|
||||
(void)s698pm_setup_irq(0, S698PM_IRQ_TIMER1, CONFIG_S698PM_TIMER1PRIO);
|
||||
#else
|
||||
(void)s698pm_setup_irq(0, S698PM_IRQ_TIMER1, 0);
|
||||
#endif
|
||||
|
||||
/* And enable the timer interrupt */
|
||||
|
||||
up_enable_irq(S698PM_IRQ_TIMER1);
|
||||
}
|
||||
195
arch/sparc/src/s698pm/s698pm-uart.h
Normal file
195
arch/sparc/src/s698pm/s698pm-uart.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm-uart.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_SPARC_SRC_S698PM_S698PM_UART_H
|
||||
#define __ARCH_SPARC_SRC_S698PM_S698PM_UART_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register Offsets *************************************************^*******/
|
||||
#define S698PM_UART_TXREG_OFFSET 0x0000 /* UARTx transmit register */
|
||||
#define S698PM_UART_RXREG_OFFSET 0x0000 /* UARTx receive register */
|
||||
#define S698PM_UART_STATREG_OFFSET 0x0004 /* UARTx status register */
|
||||
#define S698PM_UART_CTRLREG_OFFSET 0x0008 /* UARTx control register */
|
||||
#define S698PM_UART_SCALREG_OFFSET 0x000c /* UARTx scaler register */
|
||||
|
||||
/* Register Addresses *******************************************************/
|
||||
#if CHIP_NUARTS > 0
|
||||
#define S698PM_UART1_TXREG (S698PM_UART1_BASE+S698PM_UART_TXREG_OFFSET)
|
||||
#define S698PM_UART1_RXREG (S698PM_UART1_BASE+S698PM_UART_RXREG_OFFSET)
|
||||
#define S698PM_UART1_STATREG (S698PM_UART1_BASE+S698PM_UART_STATREG_OFFSET)
|
||||
#define S698PM_UART1_CTRLREG (S698PM_UART1_BASE+S698PM_UART_CTRLREG_OFFSET)
|
||||
#define S698PM_UART1_SCALREG (S698PM_UART1_BASE+S698PM_UART_SCALREG_OFFSET)
|
||||
#endif
|
||||
|
||||
#if CHIP_NUARTS > 1
|
||||
#define S698PM_UART2_TXREG (S698PM_UART2_BASE+S698PM_UART_TXREG_OFFSET)
|
||||
#define S698PM_UART2_RXREG (S698PM_UART2_BASE+S698PM_UART_RXREG_OFFSET)
|
||||
#define S698PM_UART2_STATREG (S698PM_UART2_BASE+S698PM_UART_STATREG_OFFSET)
|
||||
#define S698PM_UART2_CTRLREG (S698PM_UART2_BASE+S698PM_UART_CTRLREG_OFFSET)
|
||||
#define S698PM_UART2_SCALREG (S698PM_UART2_BASE+S698PM_UART_SCALREG_OFFSET)
|
||||
#endif
|
||||
|
||||
#if CHIP_NUARTS > 2
|
||||
#define S698PM_UART3_TXREG (S698PM_UART3_BASE+S698PM_UART_TXREG_OFFSET)
|
||||
#define S698PM_UART3_RXREG (S698PM_UART3_BASE+S698PM_UART_RXREG_OFFSET)
|
||||
#define S698PM_UART3_STATREG (S698PM_UART3_BASE+S698PM_UART_STATREG_OFFSET)
|
||||
#define S698PM_UART3_CTRLREG (S698PM_UART3_BASE+S698PM_UART_CTRLREG_OFFSET)
|
||||
#define S698PM_UART3_SCALREG (S698PM_UART3_BASE+S698PM_UART_SCALREG_OFFSET)
|
||||
#endif
|
||||
|
||||
#if CHIP_NUARTS > 3
|
||||
#define S698PM_UART4_TXREG (S698PM_UART4_BASE+S698PM_UART_TXREG_OFFSET)
|
||||
#define S698PM_UART4_RXREG (S698PM_UART4_BASE+S698PM_UART_RXREG_OFFSET)
|
||||
#define S698PM_UART4_STATREG (S698PM_UART4_BASE+S698PM_UART_STATREG_OFFSET)
|
||||
#define S698PM_UART4_CTRLREG (S698PM_UART4_BASE+S698PM_UART_CTRLREG_OFFSET)
|
||||
#define S698PM_UART4_SCALREG (S698PM_UART4_BASE+S698PM_UART_SCALREG_OFFSET)
|
||||
#endif
|
||||
|
||||
/* Register Bit-Field Definitions *******************************************/
|
||||
|
||||
#define ODD 1
|
||||
#define EVEN 0
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
#define NONE 2
|
||||
#define RX 0
|
||||
#define TX 1
|
||||
#define RXTX 3
|
||||
|
||||
/** Uart control list - Mask */
|
||||
|
||||
#define MSK_UART_ENABLE_RX 0x01
|
||||
#define MSK_UART_ENABLE_TX 0x02
|
||||
#define MSK_UART_ENABLE_RXIT 0x04
|
||||
#define MSK_UART_ENABLE_TXIT 0x08
|
||||
#define MSK_UART_PAR 0x10
|
||||
#define MSK_UART_ENABLE_PAR 0x20
|
||||
#define MSK_UART_ENABLE_FLOW 0x40
|
||||
#define MSK_UART_LOOPBACK 0x80
|
||||
#define MSK_UART_CLOCK 0x100
|
||||
#define MSK_UART_ALLINTS 0x0C
|
||||
|
||||
/* UARTx status and control register */
|
||||
|
||||
#define UART_STA_DR (1 << 0) /* Bit 0: Receive buffer data available */
|
||||
#define UART_STA_TS (1 << 1) /* Bit 1: Transmit shift register is empty */
|
||||
#define UART_STA_TE (1 << 2) /* Bit 2: TX buffer empty */
|
||||
#define UART_STA_BR (1 << 3) /* Bit 3: Transmit break */
|
||||
#define UART_STA_OV (1 << 4) /* Bit 4: overflow error status */
|
||||
#define UART_STA_PE (1 << 5) /* Bit 5: Parity error status */
|
||||
#define UART_STA_FE (1 << 6) /* Bit 6: Framing error status */
|
||||
#define UART_STA_TH (1 << 7) /* Bit 7: TX buffer 1/2 full */
|
||||
#define UART_STA_RH (1 << 8) /* Bit 8: RX buffer 1/2 full */
|
||||
#define UART_STA_TF (1 << 9) /* Bit 9: Transmit buffer full status */
|
||||
#define UART_STA_RF (1 << 10) /* Bit 10: Receive buffer full status */
|
||||
#define REG_STAT_TX_CNT (0x3f << 20)
|
||||
#define REG_STAT_RX_CNT (0x3f << 26)
|
||||
|
||||
/* UARTx transmit register */
|
||||
|
||||
#define UART_TXREG_MASK 0xff
|
||||
|
||||
/* UARTx receive register */
|
||||
|
||||
#define UART_RXREG_MASK 0xff
|
||||
|
||||
/* UARTx baud rate register */
|
||||
|
||||
#define UART_BRG_MASK 0xfff
|
||||
|
||||
#define uart_set_baudrate(baudrate) ((uint32_t)((((BOARD_CPU_CLOCK*10)/(baudrate * 8))-5)/10))
|
||||
|
||||
#define uart_parity_config(reg, uart_parity) ((uart_parity == ODD) ? \
|
||||
(reg = ((reg | MSK_UART_PAR) | MSK_UART_ENABLE_PAR)) : \
|
||||
((uart_parity == EVEN) ? \
|
||||
(reg = ((reg & ~MSK_UART_PAR) | MSK_UART_ENABLE_PAR)) : \
|
||||
(reg &= ~MSK_UART_ENABLE_PAR ) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define Uart_interrupt_config(reg, uart_its) ((uart_its == RXTX) ? \
|
||||
(reg |= (MSK_UART_ENABLE_RXIT | MSK_UART_ENABLE_TXIT)) : \
|
||||
((uart_its == RX ) ? \
|
||||
(reg |= (MSK_UART_ENABLE_RXIT & ~MSK_UART_ENABLE_TXIT)) : \
|
||||
((uart_its == TX) ? \
|
||||
(reg |= (MSK_UART_ENABLE_TXIT & ~MSK_UART_ENABLE_RXIT)) : \
|
||||
(reg &= ~(MSK_UART_ENABLE_RXIT | MSK_UART_ENABLE_TXIT)) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define uart_flow_ctrl_config(reg, uart_flow) ((uart_flow == ON) ? \
|
||||
(reg |= MSK_UART_ENABLE_FLOW) : \
|
||||
(reg &= ~MSK_UART_ENABLE_FLOW) \
|
||||
)
|
||||
|
||||
#define uart_loopback_config(reg, uart_loopb) ((uart_loopb == ON) ? \
|
||||
(reg |= MSK_UART_LOOPBACK) : \
|
||||
(reg &= ~MSK_UART_LOOPBACK) \
|
||||
)
|
||||
|
||||
#define uart_enable(reg) (reg |= (MSK_UART_ENABLE_RX | MSK_UART_ENABLE_TX))
|
||||
#define uart_disable(reg) (reg &= ~(MSK_UART_ENABLE_RX | MSK_UART_ENABLE_TX))
|
||||
|
||||
#define uart_tx_ready() ((S698PM_REG.uart_status1 & UART_STA_TF) != UART_STA_TF)
|
||||
#define uart_rx_ready() ((S698PM_REG.uart_status1 & UART_STA_DR) == UART_STA_DR)
|
||||
|
||||
#define uart_send_byte(ch) (S698PM_REG.uart_data1 = ch)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_S698PM_UART_H */
|
||||
442
arch/sparc/src/s698pm/s698pm.h
Normal file
442
arch/sparc/src/s698pm/s698pm.h
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm.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_SPARC_SRC_S698PM_S698PM_H
|
||||
#define __ARCH_SARRC_SRC_S698PM_S698PM_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include "s698pm-config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "s698pm_irq.h"
|
||||
#ifdef CONFIG_S698PM_GPIOIRQ
|
||||
#include <nuttx/irq.h>
|
||||
#include "s698pm_exti.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The following defines the bits in Memory Configuration Register 1. */
|
||||
|
||||
#define S698PM_MEMORY_CONFIGURATION_PROM_SIZE_MASK 0x0003C000
|
||||
|
||||
/* The following defines the bits in Memory Configuration Register 1. */
|
||||
|
||||
#define S698PM_MEMORY_CONFIGURATION_RAM_SIZE_MASK 0x00001E00
|
||||
|
||||
/* The following defines the bits in the Timer Control Register. */
|
||||
|
||||
/* 1 = enable counting
|
||||
* 0 = hold scalar and counter
|
||||
*/
|
||||
|
||||
#define S698PM_REG_TIMER_CONTROL_EN 0x00000001
|
||||
|
||||
/* 1 = reload at 0
|
||||
* 0 = stop at 0
|
||||
*/
|
||||
|
||||
#define S698PM_REG_TIMER_CONTROL_RL 0x00000002
|
||||
|
||||
/* 1 = load counter
|
||||
* 0 = no function
|
||||
*/
|
||||
|
||||
#define S698PM_REG_TIMER_CONTROL_LD 0x00000004
|
||||
|
||||
/* The following defines the bits in the UART Control Registers. */
|
||||
|
||||
#define S698PM_REG_UartCtrlRTD 0x000000FF /* RX/TX data */
|
||||
|
||||
/* The following defines the bits in the S698PM UART Status Registers. */
|
||||
|
||||
#define S698PM_REG_UART_STATUS_CLR 0x00000000 /* Clear all status bits */
|
||||
#define S698PM_REG_UART_STATUS_DR 0x00000001 /* Data Ready */
|
||||
#define S698PM_REG_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
|
||||
#define S698PM_REG_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
|
||||
#define S698PM_REG_UART_STATUS_BR 0x00000008 /* Break Error */
|
||||
#define S698PM_REG_UART_STATUS_OE 0x00000010 /* RX Overrun Error */
|
||||
#define S698PM_REG_UART_STATUS_PE 0x00000020 /* RX Parity Error */
|
||||
#define S698PM_REG_UART_STATUS_FE 0x00000040 /* RX Framing Error */
|
||||
#define S698PM_REG_UART_STATUS_ERR 0x00000078 /* Error Mask */
|
||||
|
||||
/* The following defines the bits in the S698PM UART Status Registers. */
|
||||
|
||||
#define S698PM_REG_UART_CTRL_RE 0x00000001 /* Receiver enable */
|
||||
#define S698PM_REG_UART_CTRL_TE 0x00000002 /* Transmitter enable */
|
||||
#define S698PM_REG_UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */
|
||||
#define S698PM_REG_UART_CTRL_TI 0x00000008 /* Transmitter interrupt enable */
|
||||
#define S698PM_REG_UART_CTRL_PS 0x00000010 /* Parity select */
|
||||
#define S698PM_REG_UART_CTRL_PE 0x00000020 /* Parity enable */
|
||||
#define S698PM_REG_UART_CTRL_FL 0x00000040 /* Flow control enable */
|
||||
#define S698PM_REG_UART_CTRL_LB 0x00000080 /* Loop Back enable */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* SPARC requires at least a 8-byte stack alignment */
|
||||
|
||||
#define SMP_STACK_ALIGNMENT 8
|
||||
#define SMP_STACK_MASK 7
|
||||
#define SMP_STACK_SIZE ((CONFIG_IDLETHREAD_STACKSIZE + 7) & ~7)
|
||||
#define SMP_STACK_WORDS (SMP_STACK_SIZE >> 2)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
extern uint32_t g_cpu0_idlestack[SMP_STACK_WORDS];
|
||||
#if CONFIG_SMP_NCPUS > 1
|
||||
extern uint32_t g_cpu1_idlestack[SMP_STACK_WORDS];
|
||||
#if CONFIG_SMP_NCPUS > 2
|
||||
extern uint32_t g_cpu2_idlestack[SMP_STACK_WORDS];
|
||||
#if CONFIG_SMP_NCPUS > 3
|
||||
extern uint32_t g_cpu3_idlestack[SMP_STACK_WORDS];
|
||||
#if CONFIG_SMP_NCPUS > 4
|
||||
# error This logic needs to extended for CONFIG_SMP_NCPUS > 4
|
||||
#endif /* CONFIG_SMP_NCPUS > 4 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 3 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 2 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 1 */
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Read CPU ID(LEON3)
|
||||
****************************************************************************/
|
||||
|
||||
#define LEON3_READ_CPUID(reg) \
|
||||
RD %asr17 , reg; \
|
||||
SRL reg , 28 , reg;
|
||||
|
||||
/****************************************************************************
|
||||
* Read CPU ID (Now only support LEON3, LEON4!)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#define READ_CPUID(reg) LEON3_READ_CPUID(reg)
|
||||
#else
|
||||
#define READ_CPUID(reg) MOV %g0 , reg
|
||||
#endif
|
||||
|
||||
/* Trap Types for on-chip peripherals
|
||||
*
|
||||
* Source: Table 8 - Interrupt Trap Type and Default Priority Assignments
|
||||
*
|
||||
* NOTE: The priority level for each source corresponds to the least
|
||||
* significant nibble of the trap type.
|
||||
*/
|
||||
|
||||
#define S698PM_TRAP_TYPE( _source ) SPARC_ASYNCHRONOUS_TRAP((_source) + 0x10)
|
||||
|
||||
#define S698PM_TRAP_SOURCE( _trap ) ((_trap) - 0x10)
|
||||
|
||||
#define S698PM_INT_TRAP( _trap ) \
|
||||
( (_trap) >= S698PM_TRAP_TYPE( S698PM_IRQ_CORRECTABLE_MEMORY_ERROR ) && \
|
||||
(_trap) <= S698PM_TRAP_TYPE( S698PM_IRQ_EMPTY6 ) )
|
||||
|
||||
static __inline__ int bsp_irq_fixup(int irq)
|
||||
{
|
||||
return irq;
|
||||
}
|
||||
|
||||
/* Macros to manipulate the Interrupt Clear, Interrupt Force, Interrupt Mask
|
||||
* and the Interrupt Pending Registers.
|
||||
*
|
||||
* NOTE: For operations which are not atomic, this code disables interrupts
|
||||
* to guarantee there are no intervening accesses to the same register
|
||||
* The operations which read the register, modify the value and then
|
||||
* store the result back are vulnerable.
|
||||
*/
|
||||
|
||||
#define S698PM_Clear_interrupt( _source ) \
|
||||
do { \
|
||||
S698PM_REG.Interrupt_Clear = (1 << (_source)); \
|
||||
} while (0)
|
||||
|
||||
#define S698PM_Force_interrupt( _source ) \
|
||||
do { \
|
||||
S698PM_REG.Interrupt_Force = (1 << (_source)); \
|
||||
} while (0)
|
||||
|
||||
#define S698PM_Is_interrupt_pending( _source ) \
|
||||
(S698PM_REG.Interrupt_Pending & (1 << (_source)))
|
||||
|
||||
#define S698PM_Is_interrupt_masked( _source ) \
|
||||
(!(S698PM_REG.Interrupt_Mask & (1 << (_source))))
|
||||
|
||||
#define S698PM_Mask_interrupt( _source ) \
|
||||
do { \
|
||||
uint32_t _level; \
|
||||
\
|
||||
_level = sparc_disable_interrupts(); \
|
||||
S698PM_REG.Interrupt_Mask &= ~(1 << (_source)); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
#define S698PM_Unmask_interrupt( _source ) \
|
||||
do { \
|
||||
uint32_t _level; \
|
||||
\
|
||||
_level = sparc_disable_interrupts(); \
|
||||
S698PM_REG.Interrupt_Mask |= (1 << (_source)); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
#define S698PM_Disable_interrupt( _source, _previous ) \
|
||||
do { \
|
||||
uint32_t _level; \
|
||||
uint32_t _mask = 1 << (_source); \
|
||||
\
|
||||
_level = sparc_disable_interrupts(); \
|
||||
(_previous) = S698PM_REG.Interrupt_Mask; \
|
||||
S698PM_REG.Interrupt_Mask = _previous & ~_mask; \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
(_previous) &= _mask; \
|
||||
} while (0)
|
||||
|
||||
#define S698PM_Restore_interrupt( _source, _previous ) \
|
||||
do { \
|
||||
uint32_t _level; \
|
||||
uint32_t _mask = 1 << (_source); \
|
||||
\
|
||||
_level = sparc_disable_interrupts(); \
|
||||
S698PM_REG.Interrupt_Mask = \
|
||||
(S698PM_REG.Interrupt_Mask & ~_mask) | (_previous); \
|
||||
sparc_enable_interrupts( _level ); \
|
||||
} while (0)
|
||||
|
||||
/* Each timer control register is organized as follows:
|
||||
*
|
||||
* D0 - Enable
|
||||
* 1 = enable counting
|
||||
* 0 = hold scaler and counter
|
||||
*
|
||||
* D1 - Counter Reload
|
||||
* 1 = reload counter at zero and restart
|
||||
* 0 = stop counter at zero
|
||||
*
|
||||
* D2 - Counter Load
|
||||
* 1 = load counter with preset value
|
||||
* 0 = no function
|
||||
*
|
||||
*/
|
||||
|
||||
#define S698PM_REG_TIMER_COUNTER_RELOAD_AT_ZERO 0x00000002
|
||||
#define S698PM_REG_TIMER_COUNTER_STOP_AT_ZERO 0x00000000
|
||||
|
||||
#define S698PM_REG_TIMER_COUNTER_LOAD_COUNTER 0x00000004
|
||||
|
||||
#define S698PM_REG_TIMER_COUNTER_ENABLE_COUNTING 0x00000001
|
||||
#define S698PM_REG_TIMER_COUNTER_DISABLE_COUNTING 0x00000000
|
||||
|
||||
#define S698PM_REG_TIMER_COUNTER_RELOAD_MASK 0x00000002
|
||||
#define S698PM_REG_TIMER_COUNTER_ENABLE_MASK 0x00000001
|
||||
|
||||
#define S698PM_REG_TIMER_COUNTER_DEFINED_MASK 0x00000003
|
||||
#define S698PM_REG_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000003
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Load 32-bit word by forcing a cache-miss */
|
||||
|
||||
static inline unsigned int s698pm_r32_no_cache(uintptr_t addr)
|
||||
{
|
||||
unsigned int tmp;
|
||||
__asm__ volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_clkinit
|
||||
*
|
||||
* Description:
|
||||
* Initialiaze clock/PLL settings per the definitions in the board.h file.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void up_clkinitialize(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_consoleinit
|
||||
*
|
||||
* Description:
|
||||
* Performs low level initialization of the console UART. This UART done
|
||||
* early so that the serial console is available for debugging very early
|
||||
* in the boot
|
||||
* sequence.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_SERIAL_CONSOLE
|
||||
void s698pm_consoleinit(void);
|
||||
#else
|
||||
# define s698pm_consoleinit()
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_uartreset
|
||||
*
|
||||
* Description:
|
||||
* Reset a UART.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
void s698pm_uartreset(uintptr_t uart_base);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_uartconfigure
|
||||
*
|
||||
* Description:
|
||||
* Configure a UART as a RS-232 UART.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_UART_DEVICE
|
||||
void s698pm_uartconfigure(uintptr_t uart_base, uint32_t baudrate,
|
||||
unsigned int parity, unsigned int nbits, bool stop2);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_boardinitialize
|
||||
*
|
||||
* Description:
|
||||
* This function must be provided by the board-specific logic in the
|
||||
* directory boards/sparc/s698pm/<board-name>/src.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void s698pm_boardinitialize(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpio_irqinitialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize all vectors to the unexpected interrupt handler
|
||||
*
|
||||
* Configuration Notes:
|
||||
* Configuration CONFIG_AVR_GPIOIRQ must be selected to enable the
|
||||
* overall GPIO IRQ feature.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during the early boot sequence before global interrupts have
|
||||
* been enabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SPARC_GPIOIRQ
|
||||
void weak_function gpio_irqinitialize(void);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpio_irqattach
|
||||
*
|
||||
* Description:
|
||||
* Attach in GPIO interrupt to the provide 'isr'
|
||||
*
|
||||
* Configuration Notes:
|
||||
* Configuration CONFIG_AVR_GPIOIRQ must be selected to enable the
|
||||
* overall GPIO IRQ feature.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SPARC_GPIOIRQ
|
||||
int gpio_irqattach(int irq, xcpt_t newisr, xcpt_t *oldisr);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpio_irqenable
|
||||
*
|
||||
* Description:
|
||||
* Enable the GPIO IRQ specified by 'irq'
|
||||
*
|
||||
* Configuration Notes:
|
||||
* Configuration CONFIG_AVR_GPIOIRQ must be selected to enable the
|
||||
* overall GPIO IRQ feature.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SPARC_GPIOIRQ
|
||||
void gpio_irqenable(int irq);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gpio_irqdisable
|
||||
*
|
||||
* Description:
|
||||
* Disable the GPIO IRQ specified by 'irq'
|
||||
*
|
||||
* Configuration Notes:
|
||||
* Configuration CONFIG_AVR_GPIOIRQ must be selected to enable the
|
||||
* overall GPIO IRQ feature.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SPARC_GPIOIRQ
|
||||
void gpio_irqdisable(int irq);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_pause_handler
|
||||
*
|
||||
* Description:
|
||||
* Inter-CPU interrupt handler
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard interrupt handler inputs
|
||||
*
|
||||
* Returned Value:
|
||||
* Should always return OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int s698pm_pause_handler(int irq, void *c, void *arg);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_S698PM_H */
|
||||
132
arch/sparc/src/s698pm/s698pm_cpuidlestack.c
Normal file
132
arch/sparc/src/s698pm/s698pm_cpuidlestack.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_cpuidlestack.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 <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
#include "s698pm.h"
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Stack alignment macros */
|
||||
|
||||
#define STACK_ISALIGNED(a) ((uintptr_t)(a) & ~SMP_STACK_MASK)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_SMP_NCPUS > 1
|
||||
static const uint32_t *g_cpu_stackalloc[CONFIG_SMP_NCPUS] =
|
||||
{
|
||||
g_cpu0_idlestack
|
||||
, g_cpu1_idlestack
|
||||
#if CONFIG_SMP_NCPUS > 2
|
||||
, g_cpu2_idlestack
|
||||
#if CONFIG_SMP_NCPUS > 3
|
||||
, g_cpu3_idlestack
|
||||
#endif /* CONFIG_SMP_NCPUS > 3 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 2 */
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_idlestack
|
||||
*
|
||||
* Description:
|
||||
* Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and
|
||||
* setup up stack-related information in the IDLE task's TCB. This
|
||||
* function is always called before up_cpu_start(). This function is
|
||||
* only called for the CPU's initial IDLE task; up_create_task is used for
|
||||
* all normal tasks, pthreads, and kernel threads for all CPUs.
|
||||
*
|
||||
* The initial IDLE task is a special case because the CPUs can be started
|
||||
* in different wans in different environments:
|
||||
*
|
||||
* 1. The CPU may already have been started and waiting in a low power
|
||||
* state for up_cpu_start(). In this case, the IDLE thread's stack
|
||||
* has already been allocated and is already in use. Here
|
||||
* up_cpu_idlestack() only has to provide information about the
|
||||
* already allocated stack.
|
||||
*
|
||||
* 2. The CPU may be disabled but started when up_cpu_start() is called.
|
||||
* In this case, a new stack will need to be created for the IDLE
|
||||
* thread and this function is then equivalent to:
|
||||
*
|
||||
* return up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL);
|
||||
*
|
||||
* The following TCB fields must be initialized by this function:
|
||||
*
|
||||
* - adj_stack_size: Stack size after adjustment for hardware, processor,
|
||||
* etc. This value is retained only for debug purposes.
|
||||
* - stack_alloc_ptr: Pointer to allocated stack
|
||||
* - stack_base_ptr: Adjusted stack base pointer after the TLS Data and
|
||||
* Arguments has been removed from the stack allocation.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - cpu: CPU index that indicates which CPU the IDLE task is
|
||||
* being created for.
|
||||
* - tcb: The TCB of new CPU IDLE task
|
||||
* - stack_size: The requested stack size for the IDLE task. At least
|
||||
* this much must be allocated. This should be
|
||||
* CONFIG_SMP_STACK_SIZE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_idlestack(int cpu, struct tcb_s *tcb, size_t stack_size)
|
||||
{
|
||||
#if CONFIG_SMP_NCPUS > 1
|
||||
uintptr_t stack_alloc;
|
||||
|
||||
DEBUGASSERT(cpu > 0 && cpu < CONFIG_SMP_NCPUS && tcb != NULL &&
|
||||
stack_size <= SMP_STACK_SIZE);
|
||||
|
||||
/* Get the top of the stack */
|
||||
|
||||
stack_alloc = (uintptr_t)g_cpu_stackalloc[cpu];
|
||||
DEBUGASSERT(stack_alloc != 0 && STACK_ISALIGNED(stack_alloc));
|
||||
|
||||
tcb->adj_stack_size = SMP_STACK_SIZE;
|
||||
tcb->stack_alloc_ptr = (void *)stack_alloc;
|
||||
tcb->stack_base_ptr = tcb->stack_alloc_ptr;
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
68
arch/sparc/src/s698pm/s698pm_cpuindex.c
Normal file
68
arch/sparc/src/s698pm/s698pm_cpuindex.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_cpuindex.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 <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include "up_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_index
|
||||
*
|
||||
* Description:
|
||||
* Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
|
||||
* corresponds to the currently executing CPU.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
|
||||
* corresponds to the currently executing CPU.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int up_cpu_index(void)
|
||||
{
|
||||
int cpu = 0;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"rd %%asr17, %0\n"
|
||||
"srl %0, 28, %0\n"
|
||||
: "=r" (cpu) : "0" (cpu)
|
||||
);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
#endif
|
||||
324
arch/sparc/src/s698pm/s698pm_cpupause.c
Normal file
324
arch/sparc/src/s698pm/s698pm_cpupause.c
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_cpupause.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 <assert.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/sched_note.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "up_internal.h"
|
||||
#include "chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* These spinlocks are used in the SMP configuration in order to implement
|
||||
* up_cpu_pause(). The protocol for CPUn to pause CPUm is as follows
|
||||
*
|
||||
* 1. The up_cpu_pause() implementation on CPUn locks both g_cpu_wait[m]
|
||||
* and g_cpu_paused[m]. CPUn then waits spinning on g_cpu_paused[m].
|
||||
* 2. CPUm receives the interrupt it (1) unlocks g_cpu_paused[m] and
|
||||
* (2) locks g_cpu_wait[m]. The first unblocks CPUn and the second
|
||||
* blocks CPUm in the interrupt handler.
|
||||
*
|
||||
* When CPUm resumes, CPUn unlocks g_cpu_wait[m] and the interrupt handler
|
||||
* on CPUm continues. CPUm must, of course, also then unlock g_cpu_wait[m]
|
||||
* so that it will be ready for the next pause operation.
|
||||
*/
|
||||
|
||||
volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
|
||||
volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_pausereq
|
||||
*
|
||||
* Description:
|
||||
* Return true if a pause request is pending for this CPU.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU to be queried
|
||||
*
|
||||
* Returned Value:
|
||||
* true = a pause request is pending.
|
||||
* false = no pasue request is pending.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool up_cpu_pausereq(int cpu)
|
||||
{
|
||||
return spin_islocked(&g_cpu_paused[cpu]);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_paused
|
||||
*
|
||||
* Description:
|
||||
* Handle a pause request from another CPU. Normally, this logic is
|
||||
* executed from interrupt handling logic within the architecture-specific
|
||||
* However, it is sometimes necessary necessary to perform the pending
|
||||
* pause operation in other contexts where the interrupt cannot be taken
|
||||
* in order to avoid deadlocks.
|
||||
*
|
||||
* This function performs the following operations:
|
||||
*
|
||||
* 1. It saves the current task state at the head of the current assigned
|
||||
* task list.
|
||||
* 2. It waits on a spinlock, then
|
||||
* 3. Returns from interrupt, restoring the state of the new task at the
|
||||
* head of the ready to run list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU to be paused
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, OK is returned. Otherwise, a negated errno value indicating
|
||||
* the nature of the failure is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_paused(int cpu)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
/* Update scheduler parameters */
|
||||
|
||||
nxsched_suspend_scheduler(tcb);
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify that we are paused */
|
||||
|
||||
sched_note_cpu_paused(tcb);
|
||||
#endif
|
||||
|
||||
/* Save the current context at CURRENT_REGS into the TCB at the head
|
||||
* of the assigned task list for this CPU.
|
||||
*/
|
||||
|
||||
up_savestate(tcb->xcp.regs);
|
||||
|
||||
/* Wait for the spinlock to be released */
|
||||
|
||||
spin_unlock(&g_cpu_paused[cpu]);
|
||||
spin_lock(&g_cpu_wait[cpu]);
|
||||
|
||||
/* Restore the exception context of the tcb at the (new) head of the
|
||||
* assigned task list.
|
||||
*/
|
||||
|
||||
tcb = this_task();
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify that we have resumed */
|
||||
|
||||
sched_note_cpu_resumed(tcb);
|
||||
#endif
|
||||
|
||||
/* Reset scheduler parameters */
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* Then switch contexts. Any necessary address environment changes
|
||||
* will be made when the interrupt returns.
|
||||
*/
|
||||
|
||||
up_restorestate(tcb->xcp.regs);
|
||||
|
||||
spin_unlock(&g_cpu_wait[cpu]);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_pause_handler
|
||||
*
|
||||
* Description:
|
||||
* Inter-CPU interrupt handler
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard interrupt handler inputs
|
||||
*
|
||||
* Returned Value:
|
||||
* Should always return OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_pause_handler(int irq, void *c, void *arg)
|
||||
{
|
||||
int cpu = up_cpu_index();
|
||||
|
||||
/* Clear IPI (Inter-Processor-Interrupt) */
|
||||
|
||||
putreg32(1 << S698PM_IPI_VECTOR, S698PM_IRQREG_ICLEAR);
|
||||
|
||||
/* Check for false alarms. Such false could occur as a consequence of
|
||||
* some deadlock breaking logic that might have already serviced the SG2
|
||||
* interrupt by calling up_cpu_paused.
|
||||
*/
|
||||
|
||||
if (up_cpu_pausereq(cpu))
|
||||
{
|
||||
/* NOTE: The following enter_critical_section() will call
|
||||
* up_cpu_paused() to process a pause request to break a deadlock
|
||||
* because the caller held a critical section. Once up_cpu_paused()
|
||||
* finished, the caller will proceed and release the g_cpu_irqlock.
|
||||
* Then this CPU will acquire g_cpu_irqlock in the function.
|
||||
*/
|
||||
|
||||
irqstate_t flags = enter_critical_section();
|
||||
|
||||
/* NOTE: the pause request should not exist here */
|
||||
|
||||
DEBUGVERIFY(!up_cpu_pausereq(cpu));
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_pause
|
||||
*
|
||||
* Description:
|
||||
* Save the state of the current task at the head of the
|
||||
* g_assignedtasks[cpu] task list and then pause task execution on the
|
||||
* CPU.
|
||||
*
|
||||
* This function is called by the OS when the logic executing on one CPU
|
||||
* needs to modify the state of the g_assignedtasks[cpu] list for another
|
||||
* CPU.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU to be stopped/
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_pause(int cpu)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
|
||||
sinfo("cpu=%d\n", cpu);
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify of the pause event */
|
||||
|
||||
sched_note_cpu_pause(this_task(), cpu);
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
|
||||
|
||||
/* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2
|
||||
* handler from returning until up_cpu_resume() is called; g_cpu_paused
|
||||
* is a handshake that will prefent this function from returning until
|
||||
* the CPU is actually paused.
|
||||
* Note that we might spin before getting g_cpu_wait, this just means that
|
||||
* the other CPU still hasn't finished responding to the previous resume
|
||||
* request.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(!spin_islocked(&g_cpu_paused[cpu]));
|
||||
|
||||
spin_lock(&g_cpu_wait[cpu]);
|
||||
spin_lock(&g_cpu_paused[cpu]);
|
||||
|
||||
/* Execute Pause IRQ to CPU(cpu) */
|
||||
|
||||
regaddr = (uintptr_t)S698PM_IRQREG_P0_FORCE + (4 * cpu);
|
||||
putreg32(1 << S698PM_IPI_VECTOR, regaddr);
|
||||
|
||||
/* Wait for the other CPU to unlock g_cpu_paused meaning that
|
||||
* it is fully paused and ready for up_cpu_resume();
|
||||
*/
|
||||
|
||||
spin_lock(&g_cpu_paused[cpu]);
|
||||
|
||||
spin_unlock(&g_cpu_paused[cpu]);
|
||||
|
||||
/* On successful return g_cpu_wait will be locked, the other CPU will be
|
||||
* spinning on g_cpu_wait and will not continue until g_cpu_resume() is
|
||||
* called. g_cpu_paused will be unlocked in any case.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_resume
|
||||
*
|
||||
* Description:
|
||||
* Restart the cpu after it was paused via up_cpu_pause(), restoring the
|
||||
* state of the task at the head of the g_assignedtasks[cpu] list, and
|
||||
* resume normal tasking.
|
||||
*
|
||||
* This function is called after up_cpu_pause in order resume operation of
|
||||
* the CPU after modifying its g_assignedtasks[cpu] list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU being re-started.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_resume(int cpu)
|
||||
{
|
||||
sinfo("cpu=%d\n", cpu);
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify of the resume event */
|
||||
|
||||
sched_note_cpu_resume(this_task(), cpu);
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
|
||||
|
||||
/* Release the spinlock. Releasing the spinlock will cause the SGI2
|
||||
* handler on 'cpu' to continue and return from interrupt to the newly
|
||||
* established thread.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
|
||||
!spin_islocked(&g_cpu_paused[cpu]));
|
||||
|
||||
spin_unlock(&g_cpu_wait[cpu]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
165
arch/sparc/src/s698pm/s698pm_cpustart.c
Normal file
165
arch/sparc/src/s698pm/s698pm_cpustart.c
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_cpustart.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 <assert.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/sched_note.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "up_internal.h"
|
||||
|
||||
#ifdef CONFIG_BUILD_KERNEL
|
||||
# include "s698pm_mmu.h"
|
||||
#endif
|
||||
|
||||
#include "s698pm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
volatile static spinlock_t g_cpu_boot;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_cpu_boot
|
||||
*
|
||||
* Description:
|
||||
* Boot handler for cpu[x]
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void s698pm_cpu_boot(void)
|
||||
{
|
||||
struct tcb_s *tcb = this_task();
|
||||
|
||||
_info("CPU%d Started\n", this_cpu());
|
||||
|
||||
/* Initialize CPU interrupts */
|
||||
|
||||
s698pm_cpuint_initialize();
|
||||
|
||||
spin_unlock(&g_cpu_boot);
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify that this CPU has started */
|
||||
|
||||
sched_note_cpu_started(tcb);
|
||||
#endif
|
||||
|
||||
/* Reset scheduler parameters */
|
||||
|
||||
nxsched_resume_scheduler(tcb);
|
||||
|
||||
/* And finally, enable cpu interrupts */
|
||||
|
||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||
up_irq_enable();
|
||||
#endif
|
||||
|
||||
/* Then transfer control to the IDLE task */
|
||||
|
||||
nx_idle_trampoline();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_cpu_start
|
||||
*
|
||||
* Description:
|
||||
* In an SMP configuration, only one CPU is initially active (CPU 0).
|
||||
* System initialization occurs on that single thread. At the completion of
|
||||
* the initialization of the OS, just before beginning normal multitasking,
|
||||
* the additional CPUs would be started by calling this function.
|
||||
*
|
||||
* Each CPU is provided the entry point to its IDLE task when started. A
|
||||
* TCB for each CPU's IDLE task has been initialized and placed in the
|
||||
* CPU's g_assignedtasks[cpu] list. No stack has been allocated or
|
||||
* initialized.
|
||||
*
|
||||
* The OS initialization logic calls this function repeatedly until each
|
||||
* CPU has been started, 1 through (CONFIG_SMP_NCPUS-1).
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of the CPU being started. This will be a numeric
|
||||
* value in the range of one to (CONFIG_SMP_NCPUS-1).
|
||||
* (CPU 0 is already active)
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_cpu_start(int cpu)
|
||||
{
|
||||
uintptr_t regaddr;
|
||||
|
||||
_info("CPU=%d\n", cpu);
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||
/* Notify of the start event */
|
||||
|
||||
sched_note_cpu_start(this_task(), cpu);
|
||||
#endif
|
||||
|
||||
/* Set the start up address */
|
||||
|
||||
regaddr = S698PM_DSU_BASE + (0x1000000 * cpu) + S698PM_DSU_PC_OFFSET;
|
||||
putreg32(CONFIG_RAM_START, regaddr);
|
||||
putreg32(0x40001000, regaddr);
|
||||
|
||||
regaddr = S698PM_DSU_BASE + (0x1000000 * cpu) + S698PM_DSU_NPC_OFFSET;
|
||||
putreg32(0x40001004, regaddr);
|
||||
|
||||
spin_lock(&g_cpu_boot);
|
||||
|
||||
/* set 1 to bit n of multiprocessor status register to active cpu n */
|
||||
|
||||
putreg32(1 << cpu, S698PM_IRQREG_MPSTATUS);
|
||||
|
||||
spin_lock(&g_cpu_boot);
|
||||
|
||||
/* prev cpu boot done */
|
||||
|
||||
spin_unlock(&g_cpu_boot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
482
arch/sparc/src/s698pm/s698pm_exceptions.S
Normal file
482
arch/sparc/src/s698pm/s698pm_exceptions.S
Normal file
|
|
@ -0,0 +1,482 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/up_exceptions.S
|
||||
*
|
||||
* 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 <arch/irq.h>
|
||||
|
||||
.file "s698pm_exceptions.S"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
.text
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
.global _ISR_Handler
|
||||
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||
.global g_cpu_intstack_top
|
||||
#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */
|
||||
.global up_doirq /* Dispatch an IRQ */
|
||||
.align 8
|
||||
/*
|
||||
* void _ISR_Handler()
|
||||
*
|
||||
* This routine provides the RTEMS interrupt management.
|
||||
*
|
||||
* We enter this handler from the 4 instructions in the trap table with
|
||||
* the following registers assumed to be set as shown:
|
||||
*
|
||||
* l0 = PSR
|
||||
* l1 = PC
|
||||
* l2 = nPC
|
||||
* l3 = trap type
|
||||
*
|
||||
* NOTE: By an executive defined convention, trap type is between 0 and 255 if
|
||||
* it is an asynchonous trap and 256 and 511 if it is synchronous.
|
||||
*/
|
||||
|
||||
_ISR_Handler:
|
||||
|
||||
/*
|
||||
* Fix the return address for synchronous traps.
|
||||
*/
|
||||
|
||||
and %l3, 0xF0, %l6
|
||||
cmp %l6, 0x10 ! Is this a synchronous trap?
|
||||
be,a win_ovflow ! No, then skip the adjustment
|
||||
nop ! DELAY
|
||||
mov %l2, %l1 ! do not return to the instruction
|
||||
add %l2, 4, %l2 ! indicated
|
||||
|
||||
win_ovflow:
|
||||
/*
|
||||
* Save the globals this block uses.
|
||||
*
|
||||
* These registers are not restored from the locals. Their contents
|
||||
* are saved directly from the locals into the ISF below.
|
||||
*/
|
||||
|
||||
mov %g4, %l4 ! save the globals this block uses
|
||||
mov %g5, %l5
|
||||
/*
|
||||
* When at a "window overflow" trap, (wim == (1 << cwp)).
|
||||
* If we get here like that, then process a window overflow.
|
||||
*/
|
||||
rd %wim, %g4
|
||||
srl %g4, %l0, %g5 ! g5 = win >> cwp ; shift count and CWP
|
||||
! are LS 5 bits ; how convenient :)
|
||||
cmp %g5, 1 ! Is this an invalid window?
|
||||
bne dont_do_the_window ! No, then skip all this stuff
|
||||
nop
|
||||
! we are using the delay slot
|
||||
|
||||
/*
|
||||
* The following is same as a 1 position right rotate of WIM
|
||||
*/
|
||||
srl %g4, 1, %g5 ! g5 = WIM >> 1
|
||||
sll %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %g4
|
||||
! g4 = WIM << (Number Windows - 1)
|
||||
or %g4, %g5, %g4 ! g4 = (WIM >> 1) |
|
||||
! (WIM << (Number Windows - 1))
|
||||
|
||||
/*
|
||||
* At this point:
|
||||
*
|
||||
* g4 = the new WIM
|
||||
* g5 is free
|
||||
*/
|
||||
|
||||
/*
|
||||
* Since we are tinkering with the register windows, we need to
|
||||
* make sure that all the required information is in global registers.
|
||||
*/
|
||||
save ! Save into the window
|
||||
wr %g4, 0, %wim ! WIM = new WIM
|
||||
nop ! delay slots
|
||||
nop
|
||||
nop
|
||||
|
||||
/*
|
||||
* Now save the window just as if we overflowed to it.
|
||||
*/
|
||||
|
||||
SAVE_WINDOW:
|
||||
std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
|
||||
std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
|
||||
std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
|
||||
std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
|
||||
|
||||
std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
|
||||
std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
|
||||
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
|
||||
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
|
||||
|
||||
restore
|
||||
nop
|
||||
|
||||
dont_do_the_window:
|
||||
/*
|
||||
* Global registers %g4 and %g5 are saved directly from %l4 and
|
||||
* %l5 directly into the ISF below.
|
||||
*/
|
||||
|
||||
save_isf:
|
||||
|
||||
/*
|
||||
* Save the state of the interrupted task -- especially the global
|
||||
* registers -- in the Interrupt Stack Frame. Note that the ISF
|
||||
* includes a regular minimum stack frame which will be used if
|
||||
* needed by register window overflow and underflow handlers.
|
||||
*
|
||||
* REGISTERS SAME AS AT _ISR_Handler
|
||||
*/
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 7
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
rd %asr17 , %g5
|
||||
srl %g5 , 28 , %g5 ! Bits 0-1=CPU ID
|
||||
#else
|
||||
mov %g0, %g5 ! CPU ID = 0
|
||||
#endif
|
||||
sll %g5, 2 , %g5 ! %g5 = CPUID * 4
|
||||
set g_cpu_intstack_top, %g4 ! %g4 = Array of stack pointers
|
||||
add %g4, %g5, %g4 ! %g4 = g_cpu_intstack_top + CPUID * 4
|
||||
ld [%g4], %g5 ! restore %sp
|
||||
sub %g5, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
|
||||
|
||||
#else
|
||||
sub %fp, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
|
||||
#endif
|
||||
|
||||
std %l0, [%sp + ISF_PSR_OFFSET] ! save psr, PC
|
||||
st %l2, [%sp + ISF_NPC_OFFSET] ! save nPC
|
||||
st %g1, [%sp + ISF_G1_OFFSET] ! save g1
|
||||
std %g2, [%sp + ISF_G2_OFFSET] ! save g2, g3
|
||||
std %l4, [%sp + ISF_G4_OFFSET] ! save g4, g5 -- see above
|
||||
std %g6, [%sp + ISF_G6_OFFSET] ! save g6, g7
|
||||
|
||||
std %i0, [%sp + ISF_I0_OFFSET] ! save i0, i1
|
||||
std %i2, [%sp + ISF_I2_OFFSET] ! save i2, i3
|
||||
std %i4, [%sp + ISF_I4_OFFSET] ! save i4, i5
|
||||
std %i6, [%sp + ISF_I6_FP_OFFSET] ! save i6/fp, i7
|
||||
|
||||
rd %y, %g1
|
||||
st %g1, [%sp + ISF_Y_OFFSET] ! save y
|
||||
|
||||
mov %sp, %o1 ! 2nd arg to ISR Handler
|
||||
|
||||
st %fsr, [%sp + ISF_FSR_OFFSET]
|
||||
std %f0, [%sp + ISF_F0_OFFSET]
|
||||
std %f2, [%sp + ISF_F2_OFFSET]
|
||||
std %f4, [%sp + ISF_F4_OFFSET]
|
||||
std %f6, [%sp + ISF_F6_OFFSET]
|
||||
std %f8, [%sp + ISF_F8_OFFSET]
|
||||
std %f10, [%sp + ISF_F10_OFFSET]
|
||||
std %f12, [%sp + ISF_F12_OFFSET]
|
||||
std %f14, [%sp + ISF_F14_OFFSET]
|
||||
std %f16, [%sp + ISF_F16_OFFSET]
|
||||
std %f18, [%sp + ISF_F18_OFFSET]
|
||||
std %f20, [%sp + ISF_F20_OFFSET]
|
||||
std %f22, [%sp + ISF_F22_OFFSET]
|
||||
std %f24, [%sp + ISF_F24_OFFSET]
|
||||
std %f26, [%sp + ISF_F26_OFFSET]
|
||||
std %f28, [%sp + ISF_F28_OFFSET]
|
||||
std %f30, [%sp + ISF_F30_OFFSET] ! total 32 word
|
||||
|
||||
fix_pil:
|
||||
mov %l0, %g5
|
||||
or %g5, SPARC_PSR_PIL_MASK, %g5 /* 0x00000F00 */
|
||||
wr %g5, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS **** /* 0x00000020 */
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
/*==========================================================================*/
|
||||
cmp %l3, 11 ! l3 = vector number
|
||||
bne do_irq
|
||||
nop
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
rd %asr17 , %l4
|
||||
srl %l4 , 28 , %l4
|
||||
#else
|
||||
mov %g0 , %l4
|
||||
#endif
|
||||
set S698PM_IRQREG_P0_EXTACK, %l5
|
||||
sll %l4, 2, %l4 ! l4 = CPUID * 4
|
||||
add %l5, %l4, %l5 ! l5 = S698PM_IRQREG_P(k)_EXTACK
|
||||
ld [%l5], %l4 ! l4 = EXTENDED_ACK
|
||||
cmp %l4, %g0
|
||||
be do_irq
|
||||
nop
|
||||
add %l4, 240, %l3 ! l3 = extended vector number
|
||||
do_irq:
|
||||
! o1 = 2nd arg = address of the ISF
|
||||
! WAS LOADED WHEN ISF WAS SAVED!!!
|
||||
mov %l3, %o0 ! o0 = 1st arg = vector number
|
||||
call up_doirq /* call ISR dispatcher */
|
||||
nop
|
||||
/*==========================================================================*/
|
||||
mov %l0, %psr ! **** DISABLE TRAPS ****
|
||||
nop;
|
||||
nop;
|
||||
nop;
|
||||
/* If a context switch occurred while processing the interrupt then
|
||||
* %o0 may have change value. If we return any value different
|
||||
* from the input regs %o1, then the lower level will know that a context
|
||||
* switch occurred during interrupt processing.
|
||||
*/
|
||||
mov %o0, %g6 ! g6 = %o0
|
||||
cmp %g6, %sp ! Is this a context switch occurred?
|
||||
be,a simple_return ! No, then skip the window save
|
||||
nop ! DELAY
|
||||
|
||||
/*
|
||||
* Flush all windows with valid contents except the current one.
|
||||
* In examining the set register windows, one may logically divide
|
||||
* the windows into sets (some of which may be empty) based on their
|
||||
* current status:
|
||||
*
|
||||
* + current (i.e. in use),
|
||||
* + used (i.e. a restore would not trap)
|
||||
* + invalid (i.e. 1 in corresponding bit in WIM)
|
||||
* + unused
|
||||
*
|
||||
* Either the used or unused set of windows may be empty.
|
||||
*
|
||||
* NOTE: We assume only one bit is set in the WIM at a time.
|
||||
*
|
||||
* Given a CWP of 5 and a WIM of 0x1, the registers are divided
|
||||
* into sets as follows:
|
||||
*
|
||||
* + 0 - invalid
|
||||
* + 1-4 - unused
|
||||
* + 5 - current
|
||||
* + 6-7 - used
|
||||
*
|
||||
* In this case, we only would save the used windows -- 6 and 7.
|
||||
*
|
||||
* Traps are disabled for the same logical period as in a
|
||||
* flush all windows trap handler.
|
||||
*
|
||||
* Register Usage while saving the windows:
|
||||
* g1 = current PSR
|
||||
* g2 = current wim
|
||||
* g3 = CWP
|
||||
* g4 = wim scratch
|
||||
* g5 = scratch
|
||||
*/
|
||||
|
||||
and %l0, SPARC_PSR_CWP_MASK, %g3 ! g3 = CWP
|
||||
andn %l0, SPARC_PSR_ET_MASK, %g1 ! g1 = psr with traps disabled
|
||||
! mov %g1, %psr ! **** DISABLE TRAPS ****
|
||||
mov %wim, %g2 ! g2 = wim
|
||||
mov 1, %g4
|
||||
sll %g4, %g3, %g4 ! g4 = WIM mask for CW invalid
|
||||
|
||||
save_frame_loop:
|
||||
sll %g4, 1, %g5 ! rotate the "wim" left 1
|
||||
srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
|
||||
or %g4, %g5, %g4 ! g4 = wim if we do one restore
|
||||
|
||||
/*
|
||||
* If a restore would not underflow, then continue.
|
||||
*/
|
||||
|
||||
andcc %g4, %g2, %g0 ! Any windows to flush?
|
||||
bnz done_flushing ! No, then continue
|
||||
nop
|
||||
|
||||
restore ! back one window
|
||||
|
||||
/*
|
||||
* Now save the window just as if we overflowed to it.
|
||||
*/
|
||||
|
||||
std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
|
||||
std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
|
||||
std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
|
||||
std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
|
||||
|
||||
std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
|
||||
std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
|
||||
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
|
||||
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
|
||||
|
||||
ba save_frame_loop
|
||||
nop
|
||||
|
||||
done_flushing:
|
||||
|
||||
! Wait three instructions after the write to PSR before using
|
||||
! non-global registers or instructions affecting the CWP
|
||||
! g1 = psr with traps disabled
|
||||
! g3 = CWP (interrupt regs window)
|
||||
mov %g1, %psr ! restore cwp
|
||||
add %g3, 1, %g2 ! calculate desired WIM
|
||||
and %g2, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g2
|
||||
mov 1, %g4
|
||||
sll %g4, %g2, %g4 ! g4 = new WIM
|
||||
mov %g4, %wim
|
||||
|
||||
mov %g6, %o0 ! %o0 = sp of context switch to
|
||||
|
||||
simple_return:
|
||||
ldd [%o0 + ISF_I6_FP_OFFSET], %i6 ! restore i6/fp, i7
|
||||
! sub %fp, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
|
||||
|
||||
ld [%o0 + ISF_Y_OFFSET], %l5 ! restore y
|
||||
wr %l5, 0, %y
|
||||
|
||||
ldd [%o0 + ISF_PSR_OFFSET], %l0 ! restore psr, PC
|
||||
|
||||
ld [%o0 + ISF_NPC_OFFSET], %l2 ! restore nPC
|
||||
rd %psr, %l3
|
||||
and %l3, SPARC_PSR_CWP_MASK, %l3 ! want "current" CWP
|
||||
andn %l0, SPARC_PSR_CWP_MASK, %l0 ! want rest from task
|
||||
or %l3, %l0, %l0 ! install it later...
|
||||
andn %l0, SPARC_PSR_ET_MASK, %l0 ! **** DISABLE TRAPS ****
|
||||
|
||||
/*
|
||||
* Restore tasks global and out registers
|
||||
*/
|
||||
ld [%o0 + ISF_G1_OFFSET], %g1 ! restore g1 ! g1 is restored later
|
||||
ldd [%o0 + ISF_G2_OFFSET], %g2 ! restore g2, g3
|
||||
ldd [%o0 + ISF_G4_OFFSET], %g4 ! restore g4, g5
|
||||
ldd [%o0 + ISF_G6_OFFSET], %g6 ! restore g6, g7
|
||||
|
||||
ldd [%o0 + ISF_I0_OFFSET], %i0 ! restore i0, i1
|
||||
ldd [%o0 + ISF_I2_OFFSET], %i2 ! restore i2, i3
|
||||
ldd [%o0 + ISF_I4_OFFSET], %i4 ! restore i4, i5
|
||||
|
||||
ldd [%o0 + ISF_F0_OFFSET] ,%f0
|
||||
ldd [%o0 + ISF_F2_OFFSET] ,%f2
|
||||
ldd [%o0 + ISF_F4_OFFSET] ,%f4
|
||||
ldd [%o0 + ISF_F6_OFFSET] ,%f6
|
||||
ldd [%o0 + ISF_F8_OFFSET] ,%f8
|
||||
ldd [%o0 + ISF_F10_OFFSET],%f10
|
||||
ldd [%o0 + ISF_F12_OFFSET],%f12
|
||||
ldd [%o0 + ISF_F14_OFFSET],%f14
|
||||
ldd [%o0 + ISF_F16_OFFSET],%f16
|
||||
ldd [%o0 + ISF_F18_OFFSET],%f18
|
||||
ldd [%o0 + ISF_F20_OFFSET],%f20
|
||||
ldd [%o0 + ISF_F22_OFFSET],%f22
|
||||
ldd [%o0 + ISF_F24_OFFSET],%f24
|
||||
ldd [%o0 + ISF_F26_OFFSET],%f26
|
||||
ldd [%o0 + ISF_F28_OFFSET],%f28
|
||||
ldd [%o0 + ISF_F30_OFFSET],%f30
|
||||
ld [%o0 + ISF_FSR_OFFSET],%fsr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
/*
|
||||
* Registers:
|
||||
*
|
||||
* ALL global registers EXCEPT G1 and the input registers have
|
||||
* already been restored and thuse off limits.
|
||||
*
|
||||
* The following is the contents of the local registers:
|
||||
*
|
||||
* %l0 = original psr
|
||||
* %l1 = return address (i.e. PC)
|
||||
* %l2 = nPC
|
||||
* %l3 = %tbr
|
||||
*/
|
||||
|
||||
/*
|
||||
* if (CWP + 1) is an invalid window then we need to reload it.
|
||||
*
|
||||
* WARNING: Traps should now be disabled
|
||||
*/
|
||||
|
||||
mov %l0, %psr ! **** DISABLE TRAPS ****
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
rd %wim, %l4
|
||||
add %l0, 1, %l6 ! l6 = cwp + 1
|
||||
and %l6, SPARC_PSR_CWP_MASK, %l6 ! do the modulo on it
|
||||
srl %l4, %l6, %l5 ! l5 = win >> cwp + 1 ; shift count
|
||||
! and CWP are conveniently LS 5 bits
|
||||
cmp %l5, 1 ! Is tasks window invalid?
|
||||
bne good_task_window
|
||||
|
||||
/*
|
||||
* The following code is the same as a 1 position left rotate of WIM.
|
||||
*/
|
||||
sll %l4, 1, %l5 ! l5 = WIM << 1
|
||||
srl %l4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l4
|
||||
! l4 = WIM >> (Number Windows - 1)
|
||||
or %l4, %l5, %l4 ! l4 = (WIM << 1) |
|
||||
! (WIM >> (Number Windows - 1))
|
||||
/*
|
||||
* Now restore the window just as if we underflowed to it.
|
||||
*/
|
||||
wr %l4, 0, %wim ! WIM = new WIM
|
||||
nop ! must delay after writing WIM
|
||||
nop
|
||||
nop
|
||||
|
||||
restore ! now into the tasks window
|
||||
|
||||
ldd [%sp + CPU_STACK_FRAME_L0_OFFSET], %l0
|
||||
ldd [%sp + CPU_STACK_FRAME_L2_OFFSET], %l2
|
||||
ldd [%sp + CPU_STACK_FRAME_L4_OFFSET], %l4
|
||||
ldd [%sp + CPU_STACK_FRAME_L6_OFFSET], %l6
|
||||
ldd [%sp + CPU_STACK_FRAME_I0_OFFSET], %i0
|
||||
ldd [%sp + CPU_STACK_FRAME_I2_OFFSET], %i2
|
||||
ldd [%sp + CPU_STACK_FRAME_I4_OFFSET], %i4
|
||||
ldd [%sp + CPU_STACK_FRAME_I6_FP_OFFSET],%i6
|
||||
! reload of sp clobbers ISF
|
||||
save ! Back to ISR dispatch window
|
||||
|
||||
good_task_window:
|
||||
|
||||
mov %l0, %psr ! **** DISABLE TRAPS ****
|
||||
nop;
|
||||
nop;
|
||||
nop
|
||||
! and restore condition codes.
|
||||
|
||||
jmp %l1 ! transfer control and
|
||||
rett %l2 ! go back to tasks window
|
||||
nop
|
||||
/* isr end */
|
||||
|
||||
/* trap handler end*/
|
||||
|
||||
.end
|
||||
678
arch/sparc/src/s698pm/s698pm_head.S
Normal file
678
arch/sparc/src/s698pm/s698pm_head.S
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_head.S
|
||||
*
|
||||
* 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 <arch/irq.h>
|
||||
|
||||
#define RTRAP(_vector, _handler) mov %g0, %l0 ; sethi %hi(_handler), %l4 ; jmp %l4+%lo(_handler); mov _vector, %l3
|
||||
#define TRAP(_vector, _handler) mov %psr, %l0; sethi %hi(_handler), %l4 ; jmp %l4+%lo(_handler); mov _vector, %l3
|
||||
|
||||
/* Unexcpected trap will halt the processor by forcing it to error state */
|
||||
#define BAD_TRAP ta 0; nop; nop; nop;
|
||||
#define SOFT_TRAP BAD_TRAP /* Software trap. Treat as BAD_TRAP */
|
||||
|
||||
/*
|
||||
* System call optimized trap table entry
|
||||
*/
|
||||
#define IRQDIS_TRAP(_handler) \
|
||||
mov %psr, %l0 ; \
|
||||
sethi %hi(_handler), %l4 ; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
or %l0, 0x0f00, %l3; ! Set PIL=0xf to disable IRQ
|
||||
|
||||
/*
|
||||
* System call optimized trap table entry
|
||||
*/
|
||||
#define IRQEN_TRAP(_handler) \
|
||||
mov %psr, %l0 ; \
|
||||
sethi %hi(_handler), %l4 ; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
andn %l0, 0xf00, %l3; ! Set PIL=0 to Enable IRQ
|
||||
|
||||
/*
|
||||
* Window Overflow optimized trap table entry
|
||||
*/
|
||||
#define WOTRAP(_vector, _handler) \
|
||||
sethi %hi(_handler), %l4; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
save; \
|
||||
nop
|
||||
|
||||
/*
|
||||
* Window Underflow optimized trap table entry
|
||||
*/
|
||||
#define WUTRAP(_vector, _handler) \
|
||||
mov %wim, %l3 ; \
|
||||
sethi %hi(_handler), %l4 ; \
|
||||
jmp %l4+%lo(_handler); \
|
||||
sll %l3, 1, %l4 ! l4 = WIM << 1
|
||||
|
||||
#define S698PM_STACK_TOP _end + (CONFIG_IDLETHREAD_STACKSIZE * CONFIG_SMP_NCPUS)
|
||||
|
||||
.text
|
||||
.global _trap_table, _hardreset
|
||||
.global __start
|
||||
.global up_lowinit /* Perform low level initialization */
|
||||
.global nx_start /* NuttX entry point */
|
||||
.global _userinit, _end
|
||||
.global _window_overflow, _window_underflow, _flush_windows, _fpdis_enable
|
||||
.global syscall_irqdis, syscall_irqen
|
||||
.global _ISR_Handler
|
||||
#ifdef CONFIG_SMP
|
||||
.global s698pm_cpu_boot
|
||||
#endif
|
||||
|
||||
/* Hardware traps */
|
||||
_trap_table:
|
||||
_hardreset:
|
||||
RTRAP(0,__start); ! 00 reset trap
|
||||
BAD_TRAP; ! 01 instruction_access_exception
|
||||
BAD_TRAP; ! 02 illegal_instruction
|
||||
BAD_TRAP; ! 03 priveleged_instruction
|
||||
TRAP(4,_fpdis_enable); ! 04 fp_disabled
|
||||
WOTRAP(5,_window_overflow); ! 05 window_overflow
|
||||
WUTRAP(6,_window_underflow); ! 06 window_underflow
|
||||
BAD_TRAP; ! 07 memory_add0ress_not_aligned
|
||||
BAD_TRAP; ! 08 fp_exception
|
||||
BAD_TRAP; ! 09 data_access_exception
|
||||
BAD_TRAP; ! 0A tag_overflow
|
||||
BAD_TRAP; ! 0B undefined
|
||||
BAD_TRAP; ! 0C undefined
|
||||
BAD_TRAP; ! 0D undefined
|
||||
BAD_TRAP; ! 0E undefined
|
||||
BAD_TRAP; ! 0F undefined
|
||||
BAD_TRAP; ! 10 undefined
|
||||
|
||||
/* Interrupt entries */
|
||||
TRAP(0x11,_ISR_Handler) ! 11 interrupt level 1
|
||||
TRAP(0x12,_ISR_Handler) ! 12 interrupt level 2
|
||||
TRAP(0x13,_ISR_Handler) ! 13 interrupt level 3
|
||||
TRAP(0x14,_ISR_Handler) ! 14 interrupt level 4
|
||||
TRAP(0x15,_ISR_Handler) ! 15 interrupt level 5
|
||||
TRAP(0x16,_ISR_Handler) ! 16 interrupt level 6
|
||||
TRAP(0x17,_ISR_Handler) ! 17 interrupt level 7
|
||||
TRAP(0x18,_ISR_Handler) ! 18 interrupt level 8
|
||||
TRAP(0x19,_ISR_Handler) ! 19 interrupt level 9
|
||||
TRAP(0x1A,_ISR_Handler) ! 1A interrupt level 1
|
||||
TRAP(0x1B,_ISR_Handler) ! 1B interrupt level 11
|
||||
TRAP(0x1C,_ISR_Handler) ! 1C interrupt level 12
|
||||
TRAP(0x1D,_ISR_Handler) ! 1D interrupt level 13
|
||||
TRAP(0x1E,_ISR_Handler) ! 1E interrupt level 14
|
||||
TRAP(0x1F,_ISR_Handler) ! 1F interrupt level 15
|
||||
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 20 - 23 undefined
|
||||
BAD_TRAP; ! 24 cp_disabled
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 25 - 27 undefined
|
||||
BAD_TRAP; ! 28 cp_exception
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 29 - 2B undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 2C - 2F undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30 - 33 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34 - 37 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38 - 3B undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3C - 3F undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40 - 43 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44 - 47 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48 - 4B undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4C - 4F undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50 - 53 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54 - 57 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58 - 5B undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5C - 5F undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60 - 63 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64 - 67 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68 - 6B undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6C - 6F undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70 - 73 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74 - 77 undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78 - 7B undefined
|
||||
BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7C - 7F undefined
|
||||
|
||||
/*
|
||||
* Software traps
|
||||
*
|
||||
* NOTE: At the risk of being redundant... this is not a full
|
||||
* table. The setjmp on the SPARC requires a window flush trap
|
||||
* handler and RTEMS will preserve the entries that were
|
||||
* installed before.
|
||||
*/
|
||||
|
||||
TRAP( 0x80, _ISR_Handler ); ! 80 halt syscall SW trap
|
||||
SOFT_TRAP; SOFT_TRAP; ! 81 - 82
|
||||
TRAP( 0x83, _flush_windows); ! 83 flush windows SW trap
|
||||
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84 - 87
|
||||
TRAP( 0x88, _ISR_Handler ); ! 88
|
||||
|
||||
/*
|
||||
* SW Trap 9-15 Reserved for Operating System
|
||||
*
|
||||
* SPARC_SWTRAP_IRQDIS
|
||||
* SPARC_SWTRAP_IRQEN
|
||||
*/
|
||||
IRQDIS_TRAP(syscall_irqdis); ! 89 IRQ Disable syscall trap
|
||||
IRQEN_TRAP(syscall_irqen); ! 8A IRQ Enable syscall trap
|
||||
|
||||
SOFT_TRAP; ! 8B
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8C - 8F
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98 - 9B
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9C - 9F
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A0 - A3
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A4 - A7
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A8 - AB
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! AC - AF
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B0 - B3
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B4 - B7
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B8 - BB
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! BC - BF
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C0 - C3
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C4 - C7
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C8 - CB
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! CC - CF
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D0 - D3
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D4 - D7
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D8 - DB
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! DC - DF
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E0 - E3
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E4 - E7
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E8 - EB
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! EC - EF
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F0 - F3
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F4 - F7
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F8 - FB
|
||||
SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! FC - FF
|
||||
|
||||
/* trap table end*/
|
||||
|
||||
/*
|
||||
* Init for SPARC-CPU
|
||||
*/
|
||||
#define PSR_INIT 0x10c0 /* Disable traps, set s and ps */
|
||||
__start:
|
||||
! initial the IU register !disable trap
|
||||
set 0x10c0, %g1
|
||||
mov %g1,%psr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
mov %g0,%wim
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
mov %g0,%g1
|
||||
mov %g0,%g2
|
||||
mov %g0,%g3
|
||||
mov %g0,%g4
|
||||
mov %g0,%g5
|
||||
mov %g0,%g6
|
||||
mov %g0,%g7
|
||||
|
||||
/*Fill local and in/out register*/
|
||||
mov 0x8,%g1
|
||||
1: mov %g0,%l0
|
||||
mov %g0,%l1
|
||||
mov %g0,%l2
|
||||
mov %g0,%l3
|
||||
mov %g0,%l4
|
||||
mov %g0,%l5
|
||||
mov %g0,%l6
|
||||
mov %g0,%l7
|
||||
mov %g0,%i0
|
||||
mov %g0,%i1
|
||||
mov %g0,%i2
|
||||
mov %g0,%i3
|
||||
mov %g0,%i4
|
||||
mov %g0,%i5
|
||||
mov %g0,%i6
|
||||
mov %g0,%i7
|
||||
subcc %g1,1,%g1
|
||||
save
|
||||
bne 1b
|
||||
flush
|
||||
nop
|
||||
|
||||
! initial the WIM register = 2
|
||||
set 2, %g1
|
||||
mov %g1, %wim
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
! initial the TBR table
|
||||
sethi %hi(_trap_table), %g1
|
||||
mov %g1, %tbr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
! enable traps,fpu in psr
|
||||
set 0x10e0, %g1
|
||||
mov %g1,%psr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
! initial the FSR register
|
||||
set _fsrinit,%g1
|
||||
ld [%g1] , %fsr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
! initial the FPU %f register
|
||||
set _fpdata,%g1
|
||||
ldd [%g1], %f0
|
||||
ldd [%g1], %f2
|
||||
ldd [%g1], %f4
|
||||
ldd [%g1], %f6
|
||||
ldd [%g1], %f8
|
||||
ldd [%g1], %f10
|
||||
ldd [%g1], %f12
|
||||
ldd [%g1], %f14
|
||||
ldd [%g1], %f16
|
||||
ldd [%g1], %f18
|
||||
ldd [%g1], %f20
|
||||
ldd [%g1], %f22
|
||||
ldd [%g1], %f24
|
||||
ldd [%g1], %f26
|
||||
ldd [%g1], %f28
|
||||
ldd [%g1], %f30
|
||||
nop
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
set CONFIG_IDLETHREAD_STACKSIZE , %l2
|
||||
rd %asr17 , %l1
|
||||
srl %l1 , 28 , %l1
|
||||
#else
|
||||
mov %g0 , %l1
|
||||
#endif
|
||||
mov %l1 , %g2
|
||||
|
||||
! initial the stack point
|
||||
sethi %hi(.Lcpu0_stacktop), %g1
|
||||
or %g1, %lo(.Lcpu0_stacktop), %g1
|
||||
1:
|
||||
cmp %l1 , 0
|
||||
beq 2f
|
||||
nop
|
||||
add %g1 , %l2 , %g1
|
||||
sub %l1 , 1 , %l1
|
||||
b 1b
|
||||
nop
|
||||
2:
|
||||
subcc %g1, CPU_MINIMUM_STACK_FRAME_SIZE, %g1
|
||||
mov %g1, %sp
|
||||
nop
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
cmp %g2 , 0
|
||||
bne s698pm_cpu_boot
|
||||
nop
|
||||
#endif
|
||||
call _userinit
|
||||
nop
|
||||
|
||||
call up_lowinit ! s698pm_lowinit.c
|
||||
nop
|
||||
|
||||
call nx_start ! sched/init/nx_start.c
|
||||
nop
|
||||
|
||||
_exit:
|
||||
ta 0
|
||||
nop
|
||||
nop
|
||||
|
||||
_userinit: /* clear the bss */
|
||||
save %sp, -64, %sp
|
||||
sethi %hi(__bss_start),%g2
|
||||
or %g2,%lo(__bss_start),%g2 ! g2 = start of bss
|
||||
sethi %hi(__stack),%g3
|
||||
or %g3,%lo(__stack),%g3 ! g3 = end of bss
|
||||
!set 0x40200000, %g3
|
||||
mov %g0,%g1 ! so std has two zeros
|
||||
sub %g3, %g2, %g3
|
||||
zerobss:
|
||||
subcc %g3, 8, %g3
|
||||
bge,a zerobss
|
||||
std %g0,[%g2+%g3]
|
||||
set _end, %o0
|
||||
st %g0,[%o0]
|
||||
nop
|
||||
|
||||
ret
|
||||
restore
|
||||
|
||||
/*
|
||||
* Init END
|
||||
*/
|
||||
|
||||
/* Number of register windows */
|
||||
#define NWINDOWS 8
|
||||
|
||||
/*
|
||||
* Window overflow trap handler.
|
||||
*
|
||||
* On entry:
|
||||
*
|
||||
* prev regwin l1 = pc
|
||||
* prev regwin l2 = npc
|
||||
*/
|
||||
.global _window_overflow
|
||||
_window_overflow:
|
||||
|
||||
/*
|
||||
* Calculate new WIM by "rotating" the valid bits in the WIM right
|
||||
* by one position. The following shows how the bits move for a SPARC
|
||||
* cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
|
||||
*
|
||||
* OLD WIM = 76543210
|
||||
* NEW WIM = 07654321
|
||||
*
|
||||
* NOTE: New WIM must be stored in a global register since the
|
||||
* "save" instruction just prior to the load of the wim
|
||||
* register will result in the local register set changing.
|
||||
*/
|
||||
|
||||
std %l0, [%sp + 0x00] ! save local register set
|
||||
std %l2, [%sp + 0x08]
|
||||
mov %wim, %l3
|
||||
sll %l3, NWINDOWS-1 , %l2
|
||||
! l2 = WIM << (Number Windows - 1)
|
||||
std %l4, [%sp + 0x10]
|
||||
std %l6, [%sp + 0x18]
|
||||
srl %l3, 1, %l3 ! l3 = WIM >> 1
|
||||
wr %l3, %l2, %wim ! WIM = (WIM >> 1) ^
|
||||
! (WIM << (Number Windows - 1))
|
||||
! 3 instruction delay not needed here
|
||||
std %i0, [%sp + 0x20] ! save input register set
|
||||
std %i2, [%sp + 0x28]
|
||||
std %i4, [%sp + 0x30]
|
||||
std %i6, [%sp + 0x38]
|
||||
restore ! Go back to trap window.
|
||||
jmp %l1 ! Re-execute save.
|
||||
rett %l2
|
||||
|
||||
/*
|
||||
* Window underflow trap handler.
|
||||
*
|
||||
* On entry:
|
||||
*
|
||||
* l1 = pc
|
||||
* l2 = npc
|
||||
* l3 = wim (from trap vector)
|
||||
* l4 = wim << 1 (from trap vector)
|
||||
*/
|
||||
.global _window_underflow
|
||||
_window_underflow:
|
||||
|
||||
/*
|
||||
* Calculate new WIM by "rotating" the valid bits in the WIM left
|
||||
* by one position. The following shows how the bits move for a SPARC
|
||||
* cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is 8.
|
||||
*
|
||||
* OLD WIM = 76543210
|
||||
* NEW WIM = 07654321
|
||||
*
|
||||
* NOTE: New WIM must be stored in a global register since the
|
||||
* "save" instruction just prior to the load of the wim
|
||||
* register will result in the local register set changing.
|
||||
*/
|
||||
|
||||
srl %l3, NWINDOWS-1, %l5
|
||||
or %l5, %l4, %l5 ! l5 = (WIM << 1) |
|
||||
! (WIM >> (Number Windows-1))
|
||||
mov %l5, %wim ! load the new WIM
|
||||
nop; nop; nop ! 3 slot delay
|
||||
restore ! Two restores to get into the
|
||||
restore ! window to restore
|
||||
ldd [%sp + 0x00], %l0 ! First the local register set
|
||||
ldd [%sp + 0x08], %l2
|
||||
ldd [%sp + 0x10], %l4
|
||||
ldd [%sp + 0x18], %l6
|
||||
ldd [%sp + 0x20], %i0 ! Then the input registers
|
||||
ldd [%sp + 0x28], %i2
|
||||
ldd [%sp + 0x30], %i4
|
||||
ldd [%sp + 0x38], %i6
|
||||
save ! Get back to the trap window.
|
||||
save
|
||||
jmp %l1 ! Re-execute restore.
|
||||
rett %l2
|
||||
|
||||
/*
|
||||
* Flush All Windows trap handler.
|
||||
*
|
||||
* Flush all windows with valid contents except the current one
|
||||
* and the one we will be returning to.
|
||||
*
|
||||
* In examining the set register windows, one may logically divide
|
||||
* the windows into sets (some of which may be empty) based on their
|
||||
* current status:
|
||||
*
|
||||
* + current (i.e. in use),
|
||||
* + used (i.e. a restore would not trap)
|
||||
* + invalid (i.e. 1 in corresponding bit in WIM)
|
||||
* + unused
|
||||
*
|
||||
* Either the used or unused set of windows may be empty.
|
||||
*
|
||||
* NOTE: We assume only one bit is set in the WIM at a time.
|
||||
*
|
||||
* Given a CWP of 5 and a WIM of 0x1, the registers are divided
|
||||
* into sets as follows:
|
||||
*
|
||||
* + 0 - invalid
|
||||
* + 1-4 - unused
|
||||
* + 5 - current
|
||||
* + 6-7 - used
|
||||
*
|
||||
* In this case, we only would save the used windows which we
|
||||
* will not be returning to -- 6.
|
||||
*
|
||||
* Register Usage while saving the windows:
|
||||
* g1 = current PSR
|
||||
* g2 = current wim
|
||||
* g3 = CWP
|
||||
* g4 = wim scratch
|
||||
* g5 = scratch
|
||||
*
|
||||
* On entry:
|
||||
*
|
||||
* l0 = psr (from trap table)
|
||||
* l1 = pc
|
||||
* l2 = npc
|
||||
*/
|
||||
.global _flush_windows
|
||||
_flush_windows:
|
||||
/*
|
||||
* Save the global registers we will be using
|
||||
*/
|
||||
|
||||
mov %g1, %l3
|
||||
mov %g2, %l4
|
||||
mov %g3, %l5
|
||||
mov %g4, %l6
|
||||
mov %g5, %l7
|
||||
|
||||
mov %l0, %g1 ! g1 = psr
|
||||
mov %wim, %g2 ! g2 = wim
|
||||
and %l0, SPARC_PSR_CWP_MASK, %g3 ! g3 = CWP
|
||||
|
||||
add %g3, 1, %g5 ! g5 = CWP + 1
|
||||
and %g5, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g5
|
||||
|
||||
mov 1, %g4
|
||||
sll %g4, %g5, %g4 ! g4 = WIM mask for CWP+1 invalid
|
||||
|
||||
restore ! go back one register window
|
||||
|
||||
save_frame_loop:
|
||||
sll %g4, 1, %g5 ! rotate the "wim" left 1
|
||||
srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
|
||||
or %g4, %g5, %g4 ! g4 = wim if we do one restore
|
||||
|
||||
/*
|
||||
* If a restore would not underflow, then continue.
|
||||
*/
|
||||
|
||||
andcc %g4, %g2, %g0 ! Any windows to flush?
|
||||
bnz done_flushing ! No, then continue
|
||||
nop
|
||||
|
||||
restore ! back one window
|
||||
|
||||
/*
|
||||
* Now save the window just as if we overflowed to it.
|
||||
*/
|
||||
|
||||
std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
|
||||
std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
|
||||
std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
|
||||
std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
|
||||
|
||||
std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
|
||||
std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
|
||||
std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
|
||||
std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
|
||||
|
||||
ba save_frame_loop
|
||||
nop
|
||||
|
||||
done_flushing:
|
||||
|
||||
add %g3, 2, %g3 ! calculate desired WIM
|
||||
and %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
|
||||
mov 1, %g4
|
||||
sll %g4, %g3, %g4 ! g4 = new WIM
|
||||
mov %g4, %wim
|
||||
|
||||
mov %g1, %psr ! restore PSR
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
/*
|
||||
* Restore the global registers we used
|
||||
*/
|
||||
|
||||
mov %l3, %g1
|
||||
mov %l4, %g2
|
||||
mov %l5, %g3
|
||||
mov %l6, %g4
|
||||
mov %l7, %g5
|
||||
|
||||
jmpl %l2, %g0
|
||||
rett %l2 + 4
|
||||
|
||||
/* fpdis_enable */
|
||||
.global _fpdis_enable
|
||||
_fpdis_enable:
|
||||
|
||||
jmpl %l2, %g0
|
||||
rett %l2 + 4
|
||||
nop
|
||||
nop
|
||||
/*************************************************/
|
||||
|
||||
/*************************************************/
|
||||
.data
|
||||
.global _fsrinit, _fpdata
|
||||
|
||||
.align 8
|
||||
_fsrinit:
|
||||
.word 0x0,0
|
||||
|
||||
.align 8
|
||||
_fpdata:
|
||||
.word 0x0,0
|
||||
|
||||
.align 8
|
||||
.global g_idle_topstack
|
||||
.type g_idle_topstack, object
|
||||
|
||||
g_idle_topstack:
|
||||
.long S698PM_STACK_TOP
|
||||
.size g_idle_topstack, .-g_idle_topstack
|
||||
|
||||
/***************************************************************************
|
||||
* .noinit section data
|
||||
***************************************************************************/
|
||||
|
||||
.section .noinit, "aw"
|
||||
|
||||
.align 8
|
||||
.globl g_cpu0_idlestack
|
||||
.type g_cpu0_idlestack, object
|
||||
|
||||
g_cpu0_idlestack:
|
||||
.space CONFIG_IDLETHREAD_STACKSIZE
|
||||
.Lcpu0_stacktop:
|
||||
.size g_cpu0_idlestack, .Lcpu0_stacktop-g_cpu0_idlestack
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#if CONFIG_SMP_NCPUS > 1
|
||||
.align 8
|
||||
.globl g_cpu1_idlestack
|
||||
.type g_cpu1_idlestack, object
|
||||
|
||||
g_cpu1_idlestack:
|
||||
.space CONFIG_IDLETHREAD_STACKSIZE
|
||||
.Lcpu1_stacktop:
|
||||
.size g_cpu1_idlestack, .Lcpu1_stacktop-g_cpu1_idlestack
|
||||
|
||||
#if CONFIG_SMP_NCPUS > 2
|
||||
.align 8
|
||||
.globl g_cpu2_idlestack
|
||||
.type g_cpu2_idlestack, object
|
||||
|
||||
g_cpu2_idlestack:
|
||||
.space CONFIG_IDLETHREAD_STACKSIZE
|
||||
.Lcpu2_stacktop:
|
||||
.size g_cpu2_idlestack, .Lcpu2_stacktop-g_cpu2_idlestack
|
||||
|
||||
#if CONFIG_SMP_NCPUS > 3
|
||||
.align 8
|
||||
.globl g_cpu3_idlestack
|
||||
.type g_cpu3_idlestack, object
|
||||
|
||||
g_cpu3_idlestack:
|
||||
.space CONFIG_IDLETHREAD_STACKSIZE
|
||||
.Lcpu3_stacktop:
|
||||
.size g_cpu3_idlestack, .Lcpu3_stacktop-g_cpu3_idlestack
|
||||
|
||||
#if CONFIG_SMP_NCPUS > 4
|
||||
# error This logic needs to extended for CONFIG_SMP_NCPUS > 4
|
||||
|
||||
#endif /* CONFIG_SMP_NCPUS > 4 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 3 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 2 */
|
||||
#endif /* CONFIG_SMP_NCPUS > 1 */
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
.end
|
||||
|
||||
116
arch/sparc/src/s698pm/s698pm_irq.h
Normal file
116
arch/sparc/src/s698pm/s698pm_irq.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_irq.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_SPARC_SRC_S698PM_S698PM_IRQ_H
|
||||
#define __ARCH_SPARC_SRC_S698PM_S698PM_IRQ_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* CPU interrupt types. */
|
||||
|
||||
#define S698PM_CPUINT_LEVEL 0
|
||||
#define S698PM_CPUINT_EDGE 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_cpuint_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize CPU interrupts
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; A negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_cpuint_initialize(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_setup_irq
|
||||
*
|
||||
* Description:
|
||||
* This function sets up the IRQ. It allocates a CPU interrupt of the given
|
||||
* priority andattaches it to the given irq.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The CPU to receive the interrupt 0~3
|
||||
* irq - The irq number from irq.h to be assigned to a EXT interrupt.
|
||||
* priority - Interrupt's priority (0~1).
|
||||
*
|
||||
* Returned Value:
|
||||
* The allocated CPU interrupt on success, a negated errno value on
|
||||
* failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_setup_irq(int cpu, int irq, int priority);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_teardown_irq
|
||||
*
|
||||
* Description:
|
||||
* This function undoes the operations done by s698pm_setup_irq.
|
||||
* It detaches a ext interrupt from a CPU irq.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The irq number from irq.h to be assigned to a EXT interrupt.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void s698pm_teardown_irq(int irq);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_S698PM_IRQ_H */
|
||||
750
arch/sparc/src/s698pm/s698pm_tim.c
Normal file
750
arch/sparc/src/s698pm/s698pm_tim.c
Normal file
|
|
@ -0,0 +1,750 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_tim.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 <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "up_internal.h"
|
||||
#include "s698pm.h"
|
||||
#include "s698pm_tim.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* This module then only compiles if there are enabled timers that are not
|
||||
* intended for some other purpose.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_S698PM_TIM1) || defined(CONFIG_S698PM_TIM2) || \
|
||||
defined(CONFIG_S698PM_TIM3) || defined(CONFIG_S698PM_TIM4)
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* TIM Device Structure */
|
||||
|
||||
struct s698pm_tim_priv_s
|
||||
{
|
||||
const struct s698pm_tim_ops_s *ops;
|
||||
enum s698pm_tim_mode_e mode;
|
||||
uint32_t base; /* TIMn base address */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Register helpers */
|
||||
|
||||
static inline uint16_t s698pm_getreg16(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset);
|
||||
static inline void s698pm_putreg16(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset, uint16_t value);
|
||||
static inline void s698pm_modifyreg32(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset, uint32_t clearbits,
|
||||
uint32_t setbits);
|
||||
static inline uint32_t s698pm_getreg32(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset);
|
||||
static inline void s698pm_putreg32(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset, uint32_t value);
|
||||
|
||||
/* Timer helpers */
|
||||
|
||||
static void s698pm_tim_reload_counter(struct s698pm_tim_dev_s *dev);
|
||||
static void s698pm_tim_enable(struct s698pm_tim_dev_s *dev);
|
||||
static void s698pm_tim_disable(struct s698pm_tim_dev_s *dev);
|
||||
static void s698pm_tim_reset(struct s698pm_tim_dev_s *dev);
|
||||
|
||||
/* Timer methods */
|
||||
|
||||
static int s698pm_tim_setmode(struct s698pm_tim_dev_s *dev,
|
||||
enum s698pm_tim_mode_e mode);
|
||||
|
||||
static int s698pm_tim_setclock(struct s698pm_tim_dev_s *dev,
|
||||
uint32_t freq);
|
||||
static uint32_t s698pm_tim_getclock(struct s698pm_tim_dev_s *dev);
|
||||
static void s698pm_tim_setperiod(struct s698pm_tim_dev_s *dev,
|
||||
uint32_t period);
|
||||
static uint32_t s698pm_tim_getperiod(struct s698pm_tim_dev_s *dev);
|
||||
static uint32_t s698pm_tim_getcounter(struct s698pm_tim_dev_s *dev);
|
||||
|
||||
static int s698pm_tim_setisr(struct s698pm_tim_dev_s *dev,
|
||||
xcpt_t handler, void *arg, int source);
|
||||
|
||||
static int s698pm_tim_checkint(struct s698pm_tim_dev_s *dev, int source);
|
||||
static void s698pm_tim_clrint(struct s698pm_tim_dev_s *dev, int source);
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct s698pm_tim_ops_s s698pm_tim_ops =
|
||||
{
|
||||
.setmode = s698pm_tim_setmode,
|
||||
.setclock = s698pm_tim_setclock,
|
||||
.getclock = s698pm_tim_getclock,
|
||||
.setperiod = s698pm_tim_setperiod,
|
||||
.getperiod = s698pm_tim_getperiod,
|
||||
.getcounter = s698pm_tim_getcounter,
|
||||
.setisr = s698pm_tim_setisr,
|
||||
.clrint = s698pm_tim_clrint,
|
||||
.checkint = s698pm_tim_checkint,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
struct s698pm_tim_priv_s s698pm_tim1_priv =
|
||||
{
|
||||
.ops = &s698pm_tim_ops,
|
||||
.mode = S698PM_TIM_MODE_UNUSED,
|
||||
.base = S698PM_TIM1_BASE,
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
struct s698pm_tim_priv_s s698pm_tim2_priv =
|
||||
{
|
||||
.ops = &s698pm_tim_ops,
|
||||
.mode = S698PM_TIM_MODE_UNUSED,
|
||||
.base = S698PM_TIM2_BASE,
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
struct s698pm_tim_priv_s s698pm_tim3_priv =
|
||||
{
|
||||
.ops = &s698pm_tim_ops,
|
||||
.mode = S698PM_TIM_MODE_UNUSED,
|
||||
.base = S698PM_TIM3_BASE,
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
struct s698pm_tim_priv_s s698pm_tim4_priv =
|
||||
{
|
||||
.ops = &s698pm_tim_ops,
|
||||
.mode = S698PM_TIM_MODE_UNUSED,
|
||||
.base = S698PM_TIM4_BASE,
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_getreg16
|
||||
*
|
||||
* Description:
|
||||
* Get a 16-bit register value by offset
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint16_t s698pm_getreg16(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset)
|
||||
{
|
||||
return getreg16(((struct s698pm_tim_priv_s *)dev)->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_putreg16
|
||||
*
|
||||
* Description:
|
||||
* Put a 16-bit register value by offset
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void s698pm_putreg16(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset, uint16_t value)
|
||||
{
|
||||
putreg16(value, ((struct s698pm_tim_priv_s *)dev)->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_modifyreg32
|
||||
*
|
||||
* Description:
|
||||
* Modify a 16-bit register value by offset
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void s698pm_modifyreg32(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset, uint32_t clearbits,
|
||||
uint32_t setbits)
|
||||
{
|
||||
modifyreg32(((struct s698pm_tim_priv_s *)dev)->base + offset, clearbits,
|
||||
setbits);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_getreg32
|
||||
*
|
||||
* Description:
|
||||
* Get a 32-bit register value by offset. This applies only for the s698pm
|
||||
* 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2-5.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t s698pm_getreg32(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset)
|
||||
{
|
||||
return getreg32(((struct s698pm_tim_priv_s *)dev)->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_putreg32
|
||||
*
|
||||
* Description:
|
||||
* Put a 32-bit register value by offset. This applies only for the s698pm
|
||||
* 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2-5.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void s698pm_putreg32(struct s698pm_tim_dev_s *dev,
|
||||
uint8_t offset, uint32_t value)
|
||||
{
|
||||
putreg32(value, ((struct s698pm_tim_priv_s *)dev)->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_reload_counter
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_tim_reload_counter(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
uint32_t val = s698pm_getreg32(dev, S698PM_TIM_CR_OFFSET);
|
||||
val |= TIMER_LOADCOUNT;
|
||||
s698pm_putreg32(dev, S698PM_TIM_CR_OFFSET, val);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_enable
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_tim_enable(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
uint32_t val = s698pm_getreg32(dev, S698PM_TIM_CR_OFFSET);
|
||||
val |= TIMER_ENABLE | TIMER_RELOADCOUNT;
|
||||
s698pm_tim_reload_counter(dev);
|
||||
s698pm_putreg32(dev, S698PM_TIM_CR_OFFSET, val);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_disable
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_tim_disable(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
uint32_t val = s698pm_getreg32(dev, S698PM_TIM_CR_OFFSET);
|
||||
val &= ~TIMER_ENABLE;
|
||||
s698pm_putreg32(dev, S698PM_TIM_CR_OFFSET, val);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_reset
|
||||
*
|
||||
* Description:
|
||||
* Reset timer into system default state, but do not affect output/input pins
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_tim_reset(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
((struct s698pm_tim_priv_s *)dev)->mode = S698PM_TIM_MODE_DISABLED;
|
||||
s698pm_tim_disable(dev);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_setmode
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_tim_setmode(struct s698pm_tim_dev_s *dev,
|
||||
enum s698pm_tim_mode_e mode)
|
||||
{
|
||||
uint32_t val = s698pm_getreg32(dev, S698PM_TIM_CR_OFFSET);
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Decode operational modes */
|
||||
|
||||
switch (mode & S698PM_TIM_MODE_MASK)
|
||||
{
|
||||
case S698PM_TIM_MODE_DISABLED:
|
||||
val &= (~TIMER_LOADCOUNT) & (~TIMER_RELOADCOUNT) & (~TIMER_ENABLE);
|
||||
break;
|
||||
|
||||
case S698PM_TIM_MODE_DOWN:
|
||||
val |= (TIMER_LOADCOUNT | TIMER_RELOADCOUNT | TIMER_ENABLE);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s698pm_tim_reload_counter(dev);
|
||||
s698pm_putreg32(dev, S698PM_TIM_CR_OFFSET, val);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_setclock
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_tim_setclock(struct s698pm_tim_dev_s *dev,
|
||||
uint32_t freq)
|
||||
{
|
||||
uint32_t freqin;
|
||||
int prescaler;
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Disable Timer? */
|
||||
|
||||
if (freq == 0)
|
||||
{
|
||||
s698pm_tim_disable(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the input clock frequency for this timer. These vary with
|
||||
* different timer clock sources, MCU-specific timer configuration, and
|
||||
* board-specific clock configuration. The correct input clock frequency
|
||||
* must be defined in the board.h header file.
|
||||
*/
|
||||
|
||||
switch (((struct s698pm_tim_priv_s *)dev)->base)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case S698PM_TIM1_BASE:
|
||||
freqin = BOARD_TIM1_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case S698PM_TIM2_BASE:
|
||||
freqin = BOARD_TIM2_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case S698PM_TIM3_BASE:
|
||||
freqin = BOARD_TIM3_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case S698PM_TIM4_BASE:
|
||||
freqin = BOARD_TIM4_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Select a pre-scaler value for this timer using the input clock
|
||||
* frequency.
|
||||
*/
|
||||
|
||||
prescaler = freqin / freq;
|
||||
|
||||
/* We need to decrement value for '1', but only, if that will not to
|
||||
* cause underflow.
|
||||
*/
|
||||
|
||||
if (prescaler > 0)
|
||||
{
|
||||
prescaler--;
|
||||
}
|
||||
|
||||
/* Check for overflow as well. */
|
||||
|
||||
if (prescaler > 0x3ff)
|
||||
{
|
||||
prescaler = 0x3ff;
|
||||
}
|
||||
|
||||
putreg32(prescaler, S698PM_TIMPRE_BASE + S698PM_TIM_PSCLOAD_OFFSET);
|
||||
putreg32(prescaler, S698PM_TIMPRE_BASE + S698PM_TIM_PSCCONT_OFFSET);
|
||||
s698pm_tim_enable(dev);
|
||||
|
||||
return prescaler;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_getclock
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t s698pm_tim_getclock(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
uint32_t freqin;
|
||||
uint32_t clock;
|
||||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Get the input clock frequency for this timer. These vary with
|
||||
* different timer clock sources, MCU-specific timer configuration, and
|
||||
* board-specific clock configuration. The correct input clock frequency
|
||||
* must be defined in the board.h header file.
|
||||
*/
|
||||
|
||||
switch (((struct s698pm_tim_priv_s *)dev)->base)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case S698PM_TIM1_BASE:
|
||||
freqin = BOARD_TIM1_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case S698PM_TIM2_BASE:
|
||||
freqin = BOARD_TIM2_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case S698PM_TIM3_BASE:
|
||||
freqin = BOARD_TIM3_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case S698PM_TIM4_BASE:
|
||||
freqin = BOARD_TIM4_FREQUENCY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* From chip datasheet, at page 1179. */
|
||||
|
||||
clock = freqin / ((0x3ff & getreg32(S698PM_TIMPRE_BASE +
|
||||
S698PM_TIM_PSCLOAD_OFFSET)) + 1);
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_setperiod
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_tim_setperiod(struct s698pm_tim_dev_s *dev,
|
||||
uint32_t period)
|
||||
{
|
||||
DEBUGASSERT(dev != NULL);
|
||||
s698pm_putreg32(dev, S698PM_TIM_ARR_OFFSET, period);
|
||||
s698pm_putreg32(dev, S698PM_TIM_CNT_OFFSET, period);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_getperiod
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t s698pm_tim_getperiod (struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
DEBUGASSERT(dev != NULL);
|
||||
return s698pm_getreg32(dev, S698PM_TIM_ARR_OFFSET);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_getcounter
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t s698pm_tim_getcounter(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
DEBUGASSERT(dev != NULL);
|
||||
uint32_t counter = s698pm_getreg32(dev, S698PM_TIM_CNT_OFFSET);
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_setisr
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_tim_setisr(struct s698pm_tim_dev_s *dev,
|
||||
xcpt_t handler, void *arg, int source)
|
||||
{
|
||||
int vectorno;
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
DEBUGASSERT(source == 0);
|
||||
|
||||
switch (((struct s698pm_tim_priv_s *)dev)->base)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case S698PM_TIM1_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case S698PM_TIM2_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case S698PM_TIM3_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case S698PM_TIM4_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER4;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
vectorno = S698PM_IRQ_TIMER1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Disable interrupt when callback is removed */
|
||||
|
||||
if (!handler)
|
||||
{
|
||||
up_disable_irq(vectorno);
|
||||
irq_detach(vectorno);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Otherwise set callback and enable interrupt */
|
||||
|
||||
irq_attach(vectorno, handler, arg);
|
||||
up_enable_irq(vectorno);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_clrint
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_tim_clrint(struct s698pm_tim_dev_s *dev, int source)
|
||||
{
|
||||
int vectorno;
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
DEBUGASSERT(source == 0);
|
||||
|
||||
switch (((struct s698pm_tim_priv_s *)dev)->base)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case S698PM_TIM1_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case S698PM_TIM2_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case S698PM_TIM3_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case S698PM_TIM4_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER4;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
up_clrpend_irq(vectorno);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_checkint
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_tim_checkint(struct s698pm_tim_dev_s *dev, int source)
|
||||
{
|
||||
int vectorno;
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
DEBUGASSERT(source == 0);
|
||||
|
||||
switch (((struct s698pm_tim_priv_s *)dev)->base)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case S698PM_TIM1_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case S698PM_TIM2_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case S698PM_TIM3_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case S698PM_TIM4_BASE:
|
||||
vectorno = S698PM_IRQ_TIMER4;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return up_pending_irq(vectorno);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Pubic Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_init
|
||||
****************************************************************************/
|
||||
|
||||
struct s698pm_tim_dev_s *s698pm_tim_init(int timer)
|
||||
{
|
||||
struct s698pm_tim_dev_s *dev = NULL;
|
||||
|
||||
/* Get structure and enable power */
|
||||
|
||||
switch (timer)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case 1:
|
||||
dev = (struct s698pm_tim_dev_s *)&s698pm_tim1_priv;
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case 2:
|
||||
dev = (struct s698pm_tim_dev_s *)&s698pm_tim2_priv;
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case 3:
|
||||
dev = (struct s698pm_tim_dev_s *)&s698pm_tim3_priv;
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case 4:
|
||||
dev = (struct s698pm_tim_dev_s *)&s698pm_tim4_priv;
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Is device already allocated */
|
||||
|
||||
if (((struct s698pm_tim_priv_s *)dev)->mode != S698PM_TIM_MODE_UNUSED)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s698pm_tim_reset(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_tim_deinit
|
||||
*
|
||||
* TODO: Detach interrupts, and close down all TIM Channels
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_tim_deinit(struct s698pm_tim_dev_s *dev)
|
||||
{
|
||||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Disable power */
|
||||
|
||||
switch (((struct s698pm_tim_priv_s *)dev)->base)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case S698PM_TIM1_BASE:
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case S698PM_TIM2_BASE:
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case S698PM_TIM3_BASE:
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case S698PM_TIM4_BASE:
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Mark it as free */
|
||||
|
||||
((struct s698pm_tim_priv_s *)dev)->mode = S698PM_TIM_MODE_UNUSED;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_S698PM_TIM1 ||...|| CONFIG_S698PM_TIM4) */
|
||||
154
arch/sparc/src/s698pm/s698pm_tim.h
Normal file
154
arch/sparc/src/s698pm/s698pm_tim.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_tim.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_SPARC_SRC_S698PM_S698PM_TIM_H
|
||||
#define __ARCH_SPARC_SRC_S698PM_S698PM_TIM_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
#define S698PM_TIM1_BASE 0x80000310
|
||||
#define S698PM_TIM2_BASE 0x80000320
|
||||
#define S698PM_TIM3_BASE 0x80000330
|
||||
#define S698PM_TIM4_BASE 0x80000340
|
||||
|
||||
#define S698PM_TIMPRE_BASE 0x80000300
|
||||
|
||||
#define S698PM_TIM_CR_OFFSET 0x0008 /* Control register 1 (16-bit) */
|
||||
#define S698PM_TIM_CNT_OFFSET 0x0000 /* Counter (16-bit) */
|
||||
#define S698PM_TIM_ARR_OFFSET 0x0004 /* Auto-reload register (16-bit) */
|
||||
|
||||
#define S698PM_TIM_PSCLOAD_OFFSET 0x0004 /* Prescaler load (16-bit) */
|
||||
#define S698PM_TIM_PSCCONT_OFFSET 0x0000 /* Prescaler count (16-bit) */
|
||||
|
||||
#define TIMER_LOADCOUNT 0x4
|
||||
#define TIMER_RELOADCOUNT 0x2
|
||||
#define TIMER_ENABLE 0x1
|
||||
|
||||
/* Helpers ******************************************************************/
|
||||
#define S698PM_TIM_SETMODE(d,mode) ((d)->ops->setmode(d,mode))
|
||||
#define S698PM_TIM_SETCLOCK(d,freq) ((d)->ops->setclock(d,freq))
|
||||
#define S698PM_TIM_GETCLOCK(d) ((d)->ops->getclock(d))
|
||||
#define S698PM_TIM_SETPERIOD(d,period) ((d)->ops->setperiod(d,period))
|
||||
#define S698PM_TIM_GETPERIOD(d) ((d)->ops->getperiod(d))
|
||||
#define S698PM_TIM_GETCOUNTER(d) ((d)->ops->getcounter(d))
|
||||
#define S698PM_TIM_SETISR(d,hnd,arg,s) ((d)->ops->setisr(d,hnd,arg,s))
|
||||
#define S698PM_TIM_CLRINT(d,s) ((d)->ops->clrint(d,s))
|
||||
#define S698PM_TIM_CHECKINT(d,s) ((d)->ops->checkint(d,s))
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* TIM Device Structure */
|
||||
|
||||
struct s698pm_tim_dev_s
|
||||
{
|
||||
struct s698pm_tim_ops_s *ops;
|
||||
};
|
||||
|
||||
enum s698pm_tim_mode_e
|
||||
{
|
||||
S698PM_TIM_MODE_UNUSED = -1,
|
||||
|
||||
/* One of the following */
|
||||
|
||||
S698PM_TIM_MODE_MASK = 0x3,
|
||||
S698PM_TIM_MODE_DISABLED = 0x1,
|
||||
S698PM_TIM_MODE_DOWN = 0x2,
|
||||
};
|
||||
|
||||
/* TIM Operations */
|
||||
|
||||
struct s698pm_tim_ops_s
|
||||
{
|
||||
/* Basic Timers */
|
||||
|
||||
int (*setmode)(struct s698pm_tim_dev_s *dev,
|
||||
enum s698pm_tim_mode_e mode);
|
||||
int (*setclock)(struct s698pm_tim_dev_s *dev, uint32_t freq);
|
||||
uint32_t (*getclock)(struct s698pm_tim_dev_s *dev);
|
||||
void (*setperiod)(struct s698pm_tim_dev_s *dev, uint32_t period);
|
||||
uint32_t (*getperiod)(struct s698pm_tim_dev_s *dev);
|
||||
uint32_t (*getcounter)(struct s698pm_tim_dev_s *dev);
|
||||
|
||||
/* Timer interrupts */
|
||||
|
||||
int (*setisr)(struct s698pm_tim_dev_s *dev,
|
||||
xcpt_t handler, void *arg, int source);
|
||||
void (*clrint)(struct s698pm_tim_dev_s *dev, int source);
|
||||
int (*checkint)(struct s698pm_tim_dev_s *dev, int source);
|
||||
};
|
||||
|
||||
/* Power-up timer and get its structure */
|
||||
|
||||
struct s698pm_tim_dev_s *s698pm_tim_init(int timer);
|
||||
|
||||
/* Power-down timer, mark it as unused */
|
||||
|
||||
int s698pm_tim_deinit(struct s698pm_tim_dev_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_timer_initialize
|
||||
*
|
||||
* Description:
|
||||
* Bind the configuration timer to a timer lower half instance and
|
||||
* register the timer drivers at 'devpath'
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The full path to the timer device. This should be of the form
|
||||
* /dev/timer0
|
||||
* timer - the timer number.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; A negated errno value is returned
|
||||
* to indicate the nature of any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_TIMER
|
||||
int s698pm_timer_initialize(const char *devpath, int timer);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_SPARC_SRC_S698PM_S698PM_TIM_H */
|
||||
488
arch/sparc/src/s698pm/s698pm_tim_lowerhalf.c
Normal file
488
arch/sparc/src/s698pm/s698pm_tim_lowerhalf.c
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
/****************************************************************************
|
||||
* arch/sparc/src/s698pm/s698pm_tim_lowerhalf.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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/timers/timer.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "s698pm_tim.h"
|
||||
|
||||
#if defined(CONFIG_TIMER) && \
|
||||
(defined(CONFIG_S698PM_TIM1) || defined(CONFIG_S698PM_TIM2)) || \
|
||||
defined(CONFIG_S698PM_TIM3) || defined(CONFIG_S698PM_TIM4))
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define S698PM_TIM1_RES 32
|
||||
#define S698PM_TIM2_RES 32
|
||||
#define S698PM_TIM3_RES 32
|
||||
#define S698PM_TIM4_RES 32
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure provides the private representation of the "lower-half"
|
||||
* driver state structure. This structure must be cast-compatible with the
|
||||
* timer_lowerhalf_s structure.
|
||||
*/
|
||||
|
||||
struct s698pm_lowerhalf_s
|
||||
{
|
||||
const struct timer_ops_s *ops; /* Lower half operations */
|
||||
struct s698pm_tim_dev_s *tim; /* stm32 timer driver */
|
||||
tccb_t callback; /* Current upper half interrupt
|
||||
* callback */
|
||||
void *arg; /* Argument passed to upper half
|
||||
* callback */
|
||||
bool started; /* True: Timer has been started */
|
||||
const uint8_t resolution; /* Number of bits in the timer
|
||||
* (16 or 32 bits) */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Interrupt handling *******************************************************/
|
||||
|
||||
static int s698pm_timer_handler(int irq, void *context, void *arg);
|
||||
|
||||
/* "Lower half" driver methods **********************************************/
|
||||
|
||||
static int s698pm_start(struct timer_lowerhalf_s *lower);
|
||||
static int s698pm_stop(struct timer_lowerhalf_s *lower);
|
||||
static int s698pm_getstatus(struct timer_lowerhalf_s *lower,
|
||||
struct timer_status_s *status);
|
||||
static int s698pm_settimeout(struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout);
|
||||
static void s698pm_setcallback(struct timer_lowerhalf_s *lower,
|
||||
tccb_t callback, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* "Lower half" driver methods */
|
||||
|
||||
static const struct timer_ops_s g_timer_ops =
|
||||
{
|
||||
.start = s698pm_start,
|
||||
.stop = s698pm_stop,
|
||||
.getstatus = s698pm_getstatus,
|
||||
.settimeout = s698pm_settimeout,
|
||||
.setcallback = s698pm_setcallback,
|
||||
.ioctl = NULL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
static struct s698pm_lowerhalf_s g_tim1_lowerhalf =
|
||||
{
|
||||
.ops = &g_timer_ops,
|
||||
.resolution = S698PM_TIM1_RES,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
static struct s698pm_lowerhalf_s g_tim2_lowerhalf =
|
||||
{
|
||||
.ops = &g_timer_ops,
|
||||
.resolution = S698PM_TIM2_RES,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
static struct s698pm_lowerhalf_s g_tim3_lowerhalf =
|
||||
{
|
||||
.ops = &g_timer_ops,
|
||||
.resolution = S698PM_TIM3_RES,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
static struct s698pm_lowerhalf_s g_tim4_lowerhalf =
|
||||
{
|
||||
.ops = &g_timer_ops,
|
||||
.resolution = S698PM_TIM4_RES,
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_timer_handler
|
||||
*
|
||||
* Description:
|
||||
* timer interrupt handler
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_timer_handler(int irq, void *context, void *arg)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *lower = (struct s698pm_lowerhalf_s *)arg;
|
||||
uint32_t next_interval_us = 0;
|
||||
|
||||
S698PM_TIM_ACKINT(lower->tim, 0);
|
||||
|
||||
if (lower->callback(&next_interval_us, lower->arg))
|
||||
{
|
||||
if (next_interval_us > 0)
|
||||
{
|
||||
S698PM_TIM_SETPERIOD(lower->tim, next_interval_us);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s698pm_stop((struct timer_lowerhalf_s *)lower);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_start
|
||||
*
|
||||
* Description:
|
||||
* Start the timer, resetting the time to the current timeout,
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower- A pointer the publicly visible representation of the "lower-half"
|
||||
* driver state structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_start(struct timer_lowerhalf_s *lower)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *priv = (struct s698pm_lowerhalf_s *)lower;
|
||||
|
||||
if (!priv->started)
|
||||
{
|
||||
S698PM_TIM_SETMODE(priv->tim, S698PM_TIM_MODE_DOWN);
|
||||
|
||||
if (priv->callback != NULL)
|
||||
{
|
||||
S698PM_TIM_SETISR(priv->tim, s698pm_timer_handler, priv, 0);
|
||||
}
|
||||
|
||||
priv->started = true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Return EBUSY to indicate that the timer was already running */
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_stop
|
||||
*
|
||||
* Description:
|
||||
* Stop the timer
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower- A pointer the publicly visible representation of the "lower-half"
|
||||
* driver state structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_stop(struct timer_lowerhalf_s *lower)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *priv = (struct s698pm_lowerhalf_s *)lower;
|
||||
|
||||
if (priv->started)
|
||||
{
|
||||
S698PM_TIM_SETMODE(priv->tim, S698PM_TIM_MODE_DISABLED);
|
||||
S698PM_TIM_SETISR(priv->tim, NULL, NULL, 0);
|
||||
priv->started = false;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Return ENODEV to indicate that the timer was not running */
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_getstatus
|
||||
*
|
||||
* Description:
|
||||
* get timer status
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - A pointer the publicly visible representation of the "lower-
|
||||
* half" driver state structure.
|
||||
* status - The location to return the status information.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_getstatus(struct timer_lowerhalf_s *lower,
|
||||
struct timer_status_s *status)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *priv = (struct s698pm_lowerhalf_s *)lower;
|
||||
uint64_t maxtimeout;
|
||||
uint32_t timeout;
|
||||
uint32_t clock;
|
||||
uint32_t period;
|
||||
uint32_t clock_factor;
|
||||
|
||||
DEBUGASSERT(priv);
|
||||
|
||||
/* Return the status bit */
|
||||
|
||||
status->flags = 0;
|
||||
if (priv->started)
|
||||
{
|
||||
status->flags |= TCFLAGS_ACTIVE;
|
||||
}
|
||||
|
||||
if (priv->callback)
|
||||
{
|
||||
status->flags |= TCFLAGS_HANDLER;
|
||||
}
|
||||
|
||||
/* Get timeout */
|
||||
|
||||
maxtimeout = (1 << priv->resolution) - 1;
|
||||
clock = S698PM_TIM_GETCLOCK(priv->tim);
|
||||
period = S698PM_TIM_GETPERIOD(priv->tim);
|
||||
|
||||
if (clock == 1000000)
|
||||
{
|
||||
timeout = period;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout = (maxtimeout * 1000000) / clock;
|
||||
}
|
||||
|
||||
status->timeout = timeout;
|
||||
|
||||
/* Get the time remaining until the timer expires (in microseconds) */
|
||||
|
||||
clock_factor = (clock == 1000000) ? 1 : (clock / 1000000);
|
||||
status->timeleft = (timeout - S698PM_TIM_GETCOUNTER(priv->tim)) *
|
||||
clock_factor;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_settimeout
|
||||
*
|
||||
* Description:
|
||||
* Set a new timeout value (and reset the timer)
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower- A pointer the publicly visible representation of the "lower-half"
|
||||
* driver state structure.
|
||||
* timeout - The new timeout value in microseconds.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s698pm_settimeout(struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *priv = (struct s698pm_lowerhalf_s *)lower;
|
||||
uint64_t maxtimeout;
|
||||
|
||||
if (priv->started)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
maxtimeout = (1 << priv->resolution) - 1;
|
||||
if (timeout > maxtimeout)
|
||||
{
|
||||
uint64_t freq = (maxtimeout * 1000000) / timeout;
|
||||
S698PM_TIM_SETCLOCK(priv->tim, freq);
|
||||
S698PM_TIM_SETPERIOD(priv->tim, maxtimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
S698PM_TIM_SETCLOCK(priv->tim, 1000000);
|
||||
S698PM_TIM_SETPERIOD(priv->tim, timeout);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_sethandler
|
||||
*
|
||||
* Description:
|
||||
* Call this user provided timeout handler.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower- A pointer the publicly visible representation of the "lower-half"
|
||||
* driver state structure.
|
||||
* callback - The new timer expiration function pointer. If this
|
||||
* function pointer is NULL, then the reset-on-expiration
|
||||
* behavior is restored,
|
||||
* arg - Argument that will be provided in the callback
|
||||
*
|
||||
* Returned Value:
|
||||
* The previous timer expiration function pointer or NULL is there was
|
||||
* no previous function pointer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void s698pm_setcallback(struct timer_lowerhalf_s *lower,
|
||||
tccb_t callback, void *arg)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *priv = (struct s698pm_lowerhalf_s *)lower;
|
||||
irqstate_t flags = enter_critical_section();
|
||||
|
||||
/* Save the new callback */
|
||||
|
||||
priv->callback = callback;
|
||||
priv->arg = arg;
|
||||
|
||||
if (callback != NULL && priv->started)
|
||||
{
|
||||
S698PM_TIM_SETISR(priv->tim, s698pm_timer_handler, priv, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
S698PM_TIM_SETISR(priv->tim, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s698pm_timer_initialize
|
||||
*
|
||||
* Description:
|
||||
* Bind the configuration timer to a timer lower half instance and
|
||||
* register the timer drivers at 'devpath'
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The full path to the timer device. This should be of the
|
||||
* form /dev/timer0
|
||||
* timer - the timer's number.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; A negated errno value is returned
|
||||
* to indicate the nature of any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s698pm_timer_initialize(const char *devpath, int timer)
|
||||
{
|
||||
struct s698pm_lowerhalf_s *lower;
|
||||
|
||||
switch (timer)
|
||||
{
|
||||
#ifdef CONFIG_S698PM_TIM1
|
||||
case 1:
|
||||
lower = &g_tim1_lowerhalf;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM2
|
||||
case 2:
|
||||
lower = &g_tim2_lowerhalf;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM3
|
||||
case 3:
|
||||
lower = &g_tim3_lowerhalf;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S698PM_TIM4
|
||||
case 4:
|
||||
lower = &g_tim4_lowerhalf;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Initialize the elements of lower half state structure */
|
||||
|
||||
lower->started = false;
|
||||
lower->callback = NULL;
|
||||
lower->tim = s698pm_tim_init(timer);
|
||||
|
||||
if (lower->tim == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Register the timer driver as /dev/timerX. The returned value from
|
||||
* timer_register is a handle that could be used with timer_unregister().
|
||||
* REVISIT: The returned handle is discard here.
|
||||
*/
|
||||
|
||||
void *drvr = timer_register(devpath, (struct timer_lowerhalf_s *)lower);
|
||||
if (drvr == NULL)
|
||||
{
|
||||
/* The actual cause of the failure may have been a failure to allocate
|
||||
* perhaps a failure to register the timer driver (such as if the
|
||||
* 'depath' were not unique). We know here but we return EEXIST to
|
||||
* indicate the failure (implying the non-unique devpath).
|
||||
*/
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TIMER */
|
||||
|
|
@ -71,7 +71,7 @@ void up_initial_state(struct tcb_s *tcb)
|
|||
if (tcb->pid == IDLE_PROCESS_ID)
|
||||
{
|
||||
tcb->stack_alloc_ptr = (void *)(g_idle_topstack -
|
||||
(CONFIG_SMP_NCPUS * CONFIG_IDLETHREAD_STACKSIZE));
|
||||
(CONFIG_SMP_NCPUS * CONFIG_IDLETHREAD_STACKSIZE));
|
||||
tcb->stack_base_ptr = tcb->stack_alloc_ptr;
|
||||
tcb->adj_stack_size = CONFIG_IDLETHREAD_STACKSIZE;
|
||||
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||
* been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
|
||||
tcb->xcp.sigdeliver = (void *)sigdeliver;
|
||||
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
|
||||
tcb->xcp.saved_npc = tcb->xcp.regs[REG_NPC];
|
||||
tcb->xcp.saved_status = tcb->xcp.regs[REG_PSR];
|
||||
|
|
@ -274,7 +274,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||
* trampoline after the signal(s) have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
|
||||
tcb->xcp.sigdeliver = (void *)sigdeliver;
|
||||
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
|
||||
tcb->xcp.saved_npc = CURRENT_REGS[REG_NPC];
|
||||
tcb->xcp.saved_status = CURRENT_REGS[REG_PSR];
|
||||
|
|
@ -330,7 +330,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||
* trampoline after the signal(s) have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
|
||||
tcb->xcp.sigdeliver = (void *)sigdeliver;
|
||||
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
|
||||
tcb->xcp.saved_npc = CURRENT_REGS[REG_NPC];
|
||||
tcb->xcp.saved_status = CURRENT_REGS[REG_PSR];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue