diff --git a/drivers/Kconfig b/drivers/Kconfig index a5795d51211..e5258c1dbb8 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -55,4 +55,6 @@ source "drivers/adc/Kconfig" source "drivers/rtc/Kconfig" +source "drivers/watchdog/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 613a0a3af7b..0d547920817 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -18,4 +18,5 @@ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_PWM) += pwm/ obj-$(CONFIG_ADC) += adc/ obj-$(CONFIG_ETHERNET) += ethernet/ +obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_RTC) += rtc/ diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig new file mode 100644 index 00000000000..a671215aaba --- /dev/null +++ b/drivers/watchdog/Kconfig @@ -0,0 +1,15 @@ +menuconfig WATCHDOG + bool + prompt "Watchdog Support" + default n + help + Include support for watchdogs. + +if WATCHDOG +config WDT_DW + bool "Enable DesignWare Watchdog" + default n + help + Enable watchdog timer. + +endif diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile new file mode 100644 index 00000000000..5796fc80396 --- /dev/null +++ b/drivers/watchdog/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_WATCHDOG) += wdt_static_irq_stubs.o +obj-$(CONFIG_WDT_DW) += wdt_dw.o diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c new file mode 100644 index 00000000000..fa15fe29b49 --- /dev/null +++ b/drivers/watchdog/wdt_dw.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015 Intel Corporation. + * + * Licensed 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 +#include +#include "wdt_dw.h" + +void (*cb_fn)(void); + +/** + * Enables the clock for the peripheral watchdog + */ +static void wdt_dw_enable(void) +{ + SCSS_PERIPHERAL->periph_cfg0 |= SCSS_PERIPH_CFG0_WDT_ENABLE; +} + +static void wdt_dw_disable(void) +{ + /* Disable the clock for the peripheral watchdog */ + SCSS_PERIPHERAL->periph_cfg0 &= ~SCSS_PERIPH_CFG0_WDT_ENABLE; +} + +void wdt_dw_isr(void) +{ + if (cb_fn) { + (*cb_fn)(); + } +} + +static void wdt_dw_get_config(struct wdt_config *config) +{ + +} + +IRQ_CONNECT_STATIC(wdt_dw, INT_WDT_IRQ, INT_WDT_IRQ_PRI, wdt_dw_isr, 0); + +static void wdt_dw_reload(void) { WDT_DW->wdt_crr = WDT_CRR_VAL; } + +static int wdt_dw_set_config(struct wdt_config *config) +{ + int ret = 0; + + wdt_dw_enable(); + /* Set timeout value + * [7:4] TOP_INIT - the initial timeout value is hardcoded in silicon, + * only bits [3:0] TOP are relevant. + * Once tickled TOP is loaded at the next expiration. + */ + uint32_t i; + uint32_t ref = (1 << 16) / (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / + 1000000); /* 2^16/FREQ_CPU */ + uint32_t timeout = config->timeout * 1000; + + for (i = 0; i < 16; i++) { + if (timeout <= ref) + break; + ref = ref << 1; + } + if (i > 15) { + ret = -1; + i = 15; + } + WDT_DW->wdt_torr = i; + + /* Set response mode */ + if (WDT_MODE_RESET == config->mode) { + WDT_DW->wdt_cr &= ~WDT_CR_INT_ENABLE; + } else { + if (config->interrupt_fn) { + cb_fn = config->interrupt_fn; + } else { + return -1; + } + + WDT_DW->wdt_cr |= WDT_CR_INT_ENABLE; + + IRQ_CONFIG(wdt_dw, INT_WDT_IRQ, 0); + irq_enable(INT_WDT_IRQ); + + /* unmask WDT interrupts to lmt */ + SCSS_INTERRUPT->int_watchdog_mask &= INT_UNMASK_IA; + } + + /* Enable WDT, cannot be disabled until soc reset */ + WDT_DW->wdt_cr |= WDT_CR_ENABLE; + + wdt_dw_reload(); + return ret; +} + +static struct wdt_driver_api wdt_dw_funcs = { + .set_config = wdt_dw_set_config, + .get_config = wdt_dw_get_config, + .enable = wdt_dw_enable, + .disable = wdt_dw_disable, + .reload = wdt_dw_reload, +}; + +int wdt_dw_init(struct device *dev) +{ + dev->driver_api = &wdt_dw_funcs; + return 0; +} + +struct wdt_dw_dev_config wdt_dev = { + .base_address = WDT_BASE_ADDR, +}; + +DECLARE_DEVICE_INIT_CONFIG(wdt, WDT_DRV_NAME, &wdt_dw_init, &wdt_dev); + +micro_early_init(wdt, NULL); diff --git a/drivers/watchdog/wdt_dw.h b/drivers/watchdog/wdt_dw.h new file mode 100644 index 00000000000..69b908018a8 --- /dev/null +++ b/drivers/watchdog/wdt_dw.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 Intel Corporation. + * + * Licensed 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 WDT_DW_H_ +#define WDT_DW_H_ + +#include +#include +#include + + +/** + * Watchdog timer register block type. + */ +struct wdt_dw { + volatile uint32_t wdt_cr; /**< Control Register */ + volatile uint32_t wdt_torr; /**< Timeout Range Register */ + volatile uint32_t wdt_ccvr; /**< Current Counter Value Register */ + volatile uint32_t wdt_crr; /**< Current Restart Register */ + volatile uint32_t wdt_stat; /**< Interrupt Status Register */ + volatile uint32_t wdt_eoi; /**< Interrupt Clear Register */ + volatile uint32_t wdt_comp_param_5; /**< Component Parameters */ + volatile uint32_t wdt_comp_param_4; /**< Component Parameters */ + volatile uint32_t wdt_comp_param_3; /**< Component Parameters */ + volatile uint32_t wdt_comp_param_2; /**< Component Parameters */ + volatile uint32_t wdt_comp_param_1; /**< Component Parameters Register 1 */ + volatile uint32_t wdt_comp_version; /**< Component Version Register */ + volatile uint32_t wdt_comp_type; /**< Component Type Register */ +}; + +/** WDT register block */ +#define WDT_DW ((struct wdt_dw *)WDT_BASE_ADDR) + + +#define WDT_CRR_VAL 0x76 +#define WDT_CR_ENABLE (1 << 0) +#define WDT_CR_INT_ENABLE (1 << 1) /* interrupt mode enable - mode1 */ + + +#define WDT_DRV_NAME "wdt_dw" + +struct wdt_dw_dev_config { + uint32_t base_address; +}; + +int wdt_dw_init(struct device *dev); + +#endif /* WDT_DW_H_ */ diff --git a/drivers/watchdog/wdt_static_irq_stubs.S b/drivers/watchdog/wdt_static_irq_stubs.S new file mode 100644 index 00000000000..8bbe1eca4f9 --- /dev/null +++ b/drivers/watchdog/wdt_static_irq_stubs.S @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Intel Corportation. + * + * Licensed 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. + */ + + +#define _ASMLANGUAGE + +#include +#include + +#if defined(CONFIG_WDT_DW) +#if defined(CONFIG_IOAPIC) + ioapic_mkstub wdt_dw wdt_dw_isr 0 +#endif /* CONFIG_IOAPIC */ +#endif + +/* externs (internal APIs) */ + +GTEXT(_IntEnt) +GTEXT(_IntExit) diff --git a/include/watchdog.h b/include/watchdog.h new file mode 100644 index 00000000000..edd5713b2e8 --- /dev/null +++ b/include/watchdog.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 Intel Corporation. + * + * Licensed 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 _WDT_H_ +#define _WDT_H_ +#include + +typedef enum { WDT_MODE_RESET = 0, WDT_MODE_INTERRUPT_RESET } wdt_mode_t; + +/** + * WDT configuration struct. + */ +struct wdt_config { + uint32_t timeout; + wdt_mode_t mode; + void (*interrupt_fn)(void); +}; + +typedef void (*wdt_api_enable)(void); +typedef void (*wdt_api_disable)(void); +typedef int (*wdt_api_set_config)(struct wdt_config *config); +typedef void (*wdt_api_get_config)(struct wdt_config *config); +typedef void (*wdt_api_reload)(void); + +struct wdt_driver_api { + wdt_api_enable enable; + wdt_api_disable disable; + wdt_api_get_config get_config; + wdt_api_set_config set_config; + wdt_api_reload reload; +}; + +static inline void wdt_enable(struct device *dev) +{ + struct wdt_driver_api *api; + + api = (struct wdt_driver_api *)dev->driver_api; + api->enable(); +} + +static inline void wdt_disable(struct device *dev) +{ + struct wdt_driver_api *api; + + api = (struct wdt_driver_api *)dev->driver_api; + api->disable(); +} + +static inline void wdt_get_config(struct device *dev, struct wdt_config *config) +{ + struct wdt_driver_api *api; + + api = (struct wdt_driver_api *)dev->driver_api; + api->get_config(config); +} + +static inline int wdt_set_config(struct device *dev, struct wdt_config *config) +{ + struct wdt_driver_api *api; + + api = (struct wdt_driver_api *)dev->driver_api; + return api->set_config(config); +} + +static inline void wdt_reload(struct device *dev) +{ + struct wdt_driver_api *api; + + api = (struct wdt_driver_api *)dev->driver_api; + api->reload(); +} + +#endif