blob: e835cffe167f9224e951b86d675ea5c6265ae056 [file] [log] [blame]
/****************************************************************************
* arch/arm/src/phy62xx/phyplus_wdt.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/clock.h>
#include <nuttx/timers/watchdog.h>
#include <arch/board/board.h>
#include "phyplus_wdt.h"
#include "jump_function.h"
#include "mcu_phy_bumbee.h"
#include "clock.h"
#if defined(CONFIG_WATCHDOG)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define WATCHDOG_1000MS_EVENT 0x0001
#define WATCHDOG_1000MS_CYCLE 1000
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure provides the private representation of the "lower-half"
* driver state structure. This structure must be cast-compatible with the
* well-known watchdog_lowerhalf_s structure.
*/
void __attribute__((used)) hal_WATCHDOG_IRQHandler(void)
{
volatile uint32_t a;
a = AP_WDT->EOI;
AP_WDT->CRR = 0x76;
}
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* "Lower half" driver methods **********************************************/
static int phyplus_wdt_start(struct watchdog_lowerhalf_s *lower);
static int phyplus_wdt_stop(struct watchdog_lowerhalf_s *lower);
static int phyplus_wdt_keepalive(struct watchdog_lowerhalf_s *lower);
static int phyplus_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status);
static int phyplus_wdt_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout);
/****************************************************************************
* Private Data
****************************************************************************/
/* "Lower half" driver methods */
static const struct watchdog_ops_s g_wdgops =
{
.start = phyplus_wdt_start,
.stop = phyplus_wdt_stop,
.keepalive = phyplus_wdt_keepalive,
.getstatus = phyplus_wdt_getstatus,
.settimeout = phyplus_wdt_settimeout,
.capture = NULL, /* phyplus_wdt_capture, */
.ioctl = NULL, /* phyplus_wdt_ioctl, */
};
struct phyplus_lowerhalf_s
{
const struct watchdog_ops_s *ops; /* Lower half operations */
bool started; /* true: The watchdog timer has been started */
bool intr_mode; /* 0: not use intr_callback handle, 1: use intr_callback handle */
WDG_CYCLE_Type_e wdt_cycle;
};
static struct phyplus_lowerhalf_s g_wdgdev;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int pp_watchdog_init(void)
{
wdinfo("pp_init\n");
uint8_t delay;
hal_clk_gate_enable(MOD_WDT);
/* wdt_reset_en : software reset enable */
/* 1---enable 0---disable */
if ((AP_PCR->SW_RESET0 & 0x04) == 0)
{
AP_PCR->SW_RESET0 |= 0x04;
delay = 20;
while (delay-- > 0);
}
/* wdt software reset enable in 0xc */
/* 1---enable 0---disable */
if ((AP_PCR->SW_RESET2 & 0x04) == 0)
{
AP_PCR->SW_RESET2 |= 0x04;
delay = 20;
while (delay-- > 0);
}
/* watchdog software reset */
/* 1---normal 0---reset */
AP_PCR->SW_RESET2 &= ~0x20;
delay = 20;
while (delay-- > 0);
AP_PCR->SW_RESET2 |= 0x20;
delay = 20;
while (delay-- > 0);
return 0;
}
static int pp_watchdog_start(bool interrupt_mode, WDG_CYCLE_Type_e cycle)
{
wdinfo("pp_start\n");
volatile uint32_t a;
a = AP_WDT->EOI;
AP_WDT->TORR = cycle;
if (TRUE == interrupt_mode)
{
JUMP_FUNCTION(WDT_IRQ_HANDLER) = (uint32_t)&hal_WATCHDOG_IRQHandler;
AP_WDT->CR = 0x1f;
NVIC_SetPriority((IRQn_Type)WDT_IRQn, IRQ_PRIO_HAL);
NVIC_EnableIRQ((IRQn_Type)WDT_IRQn);
}
else
{
JUMP_FUNCTION(WDT_IRQ_HANDLER) = 0;
AP_WDT->CR = 0x1d;
NVIC_DisableIRQ((IRQn_Type)WDT_IRQn);
}
AP_WDT->CRR = 0x76;
return 0;
}
static int pp_watchdog_stop(void)
{
wdinfo("pp_stop not support\n");
/* phyplus current not support stop watchdog while watchdog is running */
return 0;
}
static int __attribute__((used)) pp_watchdog_settimer(WDG_CYCLE_Type_e cycle)
{
wdinfo("pp_settimer\n");
AP_WDT->TORR = cycle;
return 0;
}
static int pp_watchdog_feed(void)
{
wdinfo("pp_feed\n");
AP_WDT->CRR = 0x76;
return 0;
}
/****************************************************************************
* Name: phyplus_wdt_start
*
* Description:
* Start the watchdog 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 phyplus_wdt_start(struct watchdog_lowerhalf_s *lower)
{
struct phyplus_lowerhalf_s *priv =
(struct phyplus_lowerhalf_s *)lower;
irqstate_t flags;
wdinfo("wdt_start\n");
DEBUGASSERT(priv);
/* Have we already been started? */
if (!priv->started)
{
/* Enable IWDG (the LSI oscillator will be enabled by hardware). NOTE:
* If the "Hardware watchdog" feature is enabled through the device
* option bits, the watchdog is automatically enabled at power-on.
*/
flags = enter_critical_section();
pp_watchdog_start(priv->intr_mode, priv->wdt_cycle);
priv->started = true;
leave_critical_section(flags);
}
return OK;
}
/****************************************************************************
* Name: phyplus_wdt_stop
*
* Description:
* Stop the watchdog 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 phyplus_wdt_stop(struct watchdog_lowerhalf_s *lower)
{
struct phyplus_lowerhalf_s *priv =
(struct phyplus_lowerhalf_s *)lower;
wdinfo("wdt_stop\n");
if (priv->started)
{
priv->started = false;
pp_watchdog_stop();
}
return -ENOSYS;
}
/****************************************************************************
* Name: phyplus_wdt_keepalive
*
* Description:
* Reset the watchdog timer to the current timeout value, prevent any
* imminent watchdog timeouts. This is sometimes referred as "pinging"
* the watchdog timer or "petting the dog".
*
* 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 phyplus_wdt_keepalive(struct watchdog_lowerhalf_s *lower)
{
/* struct phyplus_lowerhalf_s *priv =
* (struct phyplus_lowerhalf_s *)lower;
*/
irqstate_t flags;
wdinfo("wdt_feed\n");
flags = enter_critical_section();
pp_watchdog_feed();
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: phyplus_wdt_getstatus
*
* Description:
* Get the current watchdog timer status
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
* status - The location to return the watchdog status information.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int phyplus_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status)
{
struct phyplus_lowerhalf_s *priv =
(struct phyplus_lowerhalf_s *)lower;
DEBUGASSERT(priv);
wdinfo("wdt getstatus\n");
wdinfo("CR:%08x , TORR:%08lx , CCVR:%08lx , STAT:%08x\n", AP_WDT->CR ,
AP_WDT->TORR , AP_WDT->CCVR , AP_WDT->STAT);
if (priv->started)
{
status->flags |= WDFLAGS_ACTIVE;
}
else
{
status->flags |= WDFLAGS_RESET;
}
status->timeout = 0x0;
status->timeleft = AP_WDT->CCVR;
return OK;
}
/****************************************************************************
* Name: phhyplus_wdt_settimeout
*
* Description:
* Set a new timeout value (and reset the watchdog timer)
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
* timeout - The new timeout value in milliseconds.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int phyplus_wdt_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout)
{
struct phyplus_lowerhalf_s *priv =
(struct phyplus_lowerhalf_s *)lower;
wdinfo("wdt set timeout timeout=%lu\n", timeout);
timeout = timeout / 1000;
if (timeout < 4)
{
priv->wdt_cycle = WDG_2S;
}
else if((timeout < 8) && (timeout >= 4))
{
priv->wdt_cycle = WDG_4S;
}
else if((timeout < 16) && (timeout >= 8))
{
priv->wdt_cycle = WDG_8S;
}
else if((timeout < 32) && (timeout >= 16))
{
priv->wdt_cycle = WDG_16S;
}
else if((timeout < 64) && (timeout >= 32))
{
priv->wdt_cycle = WDG_32S;
}
else if((timeout < 128) && (timeout >= 64))
{
priv->wdt_cycle = WDG_64S;
}
else if((timeout < 256) && (timeout >= 128))
{
priv->wdt_cycle = WDG_128S;
}
else if(timeout > 256)
{
priv->wdt_cycle = WDG_256S;
}
AP_WDT->TORR = priv->wdt_cycle;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: phyplus_wdt_initialize
*
* Description:
* Initialize the IWDG watchdog timer. The watchdog timer is initialized
* and registers as 'devpath'. The initial state of the watchdog timer is
* disabled.
*
* Input Parameters:
* devpath - The full path to the watchdog. This should be of the form
* /dev/watchdog0
* lsifreq - The calibrated LSI clock frequency
*
* Returned Value:
* None
*
****************************************************************************/
void phyplus_wdt_initialize(const char *devpath)
{
struct phyplus_lowerhalf_s *priv = &g_wdgdev;
wdinfo("wdt initialize\n");
/* Initialize the driver state structure. */
priv->ops = &g_wdgops;
priv->started = false;
priv->intr_mode = false;
priv->wdt_cycle = WDG_2S;
pp_watchdog_init();
watchdog_register(devpath, (struct watchdog_lowerhalf_s *)priv);
}
#endif /* CONFIG_WATCHDOG */