summaryrefslogtreecommitdiff
path: root/zephyr
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2021-03-31 20:42:23 -0700
committerCommit Bot <commit-bot@chromium.org>2021-04-20 05:17:59 +0000
commit1de253b7871a1ee050cf809bb5a9eb7ef21f367a (patch)
tree75f6a16ae4eadae054df08097d6518b0569f005a /zephyr
parent9aae5cd8035ab42ab153f5a6e87ba6745ee58360 (diff)
downloadchrome-ec-1de253b7871a1ee050cf809bb5a9eb7ef21f367a.tar.gz
zephyr: npcx: Add non-psl hibernate implementation
Implements non-psl hibernate mechanism for cros_system driver. First, we plan a little hibernate function locates in the last 32K ram block in npcx7 series. Then power down the other ram blocks and go to deep sleep mode for better power consumptions. Please notice do not use global or call the other functions in this hibernate utility since we have turned off the other ram blocks. BUG=b:177904393, b:183745774 BRANCH=none TEST=zmake testall TEST=All wake-up GPIOs can wake-up ec from hibernating on npcx7 evb. Signed-off-by: Mulin Chao <mlchao@nuvoton.com> Signed-off-by: Wealian Liao <whliao@nuvoton.corp-partner.google.com> Change-Id: I48f95b0e616ad27f77a6d0ada8251ec438427741 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2821116 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-by: Keith Short <keithshort@chromium.org> Commit-Queue: Keith Short <keithshort@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2839172 Tested-by: Eric Yilun Lin <yllin@chromium.org> Reviewed-by: Eric Yilun Lin <yllin@chromium.org> Commit-Queue: Eric Yilun Lin <yllin@chromium.org> Commit-Queue: Ting Shen <phoenixshen@chromium.org>
Diffstat (limited to 'zephyr')
-rw-r--r--zephyr/drivers/cros_system/cros_system_npcx.c364
-rw-r--r--zephyr/dts/bindings/gpio/gpio-enum-name.yaml1
-rw-r--r--zephyr/dts/bindings/gpio/hibernate-wake-pins.yaml13
-rw-r--r--zephyr/linker/CMakeLists.txt4
-rw-r--r--zephyr/linker/npcx-lfw.ld10
-rw-r--r--zephyr/projects/trogdor/lazor/gpio.dts1
-rw-r--r--zephyr/shim/src/system.c10
7 files changed, 359 insertions, 44 deletions
diff --git a/zephyr/drivers/cros_system/cros_system_npcx.c b/zephyr/drivers/cros_system/cros_system_npcx.c
index 82d95427af..07a7cf8c80 100644
--- a/zephyr/drivers/cros_system/cros_system_npcx.c
+++ b/zephyr/drivers/cros_system/cros_system_npcx.c
@@ -3,14 +3,61 @@
* found in the LICENSE file.
*/
+#include <arch/arm/aarch32/cortex_m/cmsis.h>
#include <drivers/cros_system.h>
+#include <drivers/gpio.h>
#include <drivers/watchdog.h>
#include <logging/log.h>
#include <soc.h>
+#include <soc/nuvoton_npcx/reg_def_cros.h>
+#include <sys/util.h>
+
+#include "gpio.h"
#include "rom_chip.h"
+#include "soc_gpio.h"
+#include "soc_miwu.h"
+#include "system.h"
LOG_MODULE_REGISTER(cros_system, LOG_LEVEL_ERR);
+/**
+ * @brief Get a node from path '/hibernate_wakeup_pins' which has a property
+ * 'wakeup-pins' contains GPIO list for hibernate wake-up
+ *
+ * @return node identifier with that path.
+ */
+#define SYSTEM_DT_NODE_HIBERNATE_CONFIG DT_INST(0, cros_ec_hibernate_wake_pins)
+
+/**
+ * @brief Get the length of 'wakeup-pins' property
+ *
+ * @return length of 'wakeup-pins' prop which type is 'phandles'
+ */
+#define SYSTEM_DT_NODE_WAKEUP_PIN_LEN \
+ DT_PROP_LEN(SYSTEM_DT_NODE_HIBERNATE_CONFIG, wakeup_pins)
+
+/**
+ * @brief Get a node identifier from a phandle in property 'wakeup-pins' at
+ * index i.
+ *
+ * @param i index of 'wakeup-pins' prop which type is 'phandles'
+ * @return node identifier with that path.
+ */
+#define SYSTEM_DT_NODE_WAKEUP_PIN_BY_IDX(i) \
+ DT_PHANDLE_BY_IDX(SYSTEM_DT_NODE_HIBERNATE_CONFIG, wakeup_pins, i)
+
+/**
+ * @brief Get the enum using in chromium system by index i in 'wakeup-pins'
+ * list.
+ *
+ * @param i index of 'wakeup-pins' prop which type is 'phandles'
+ * @return GPIO enumeration
+ */
+#define SYSTEM_DT_WAKEUP_GPIO_ENUM_BY_IDX(i, _) \
+ COND_CODE_1(DT_NODE_HAS_PROP(SYSTEM_DT_NODE_WAKEUP_PIN_BY_IDX(i), \
+ enum_name), \
+ (GPIO_SIGNAL(SYSTEM_DT_NODE_WAKEUP_PIN_BY_IDX(i)), ), ())
+
/* Driver config */
struct cros_system_npcx_config {
/* hardware module base address */
@@ -45,14 +92,245 @@ enum npcx_chip_id {
DEVICE_ID_NPCX797W_C = 0x2C,
};
+/* RAM block size in npcx family (Unit: bytes) */
+#define NPCX_RAM_BLOCK_SIZE (32 * 1024)
+/* RAM block number in npcx7 series */
+#define NPCX7_RAM_BLOCK_NUM 12
+/* RAM block mask for power down in npcx7 series */
+#define NPCX7_RAM_BLOCK_PD_MASK (BIT(12) - 1)
+/* Get saved reset flag address in battery-backed ram */
+#define BBRAM_SAVED_RESET_FLAG_ADDR \
+ (DT_REG_ADDR(DT_INST(0, nuvoton_npcx_cros_bbram)) + \
+ DT_PROP(DT_PATH(named_bbram_regions, saved_reset_flags), offset))
+
+/* Soc specific system local functions */
+static int system_npcx_watchdog_stop(void)
+{
+ if (IS_ENABLED(CONFIG_WATCHDOG)) {
+ const struct device *wdt_dev = device_get_binding(
+ DT_LABEL(DT_INST(0, nuvoton_npcx_watchdog)));
+
+ if (!wdt_dev) {
+ LOG_ERR("wdt_dev get binding failed");
+ return -ENODEV;
+ }
+
+ wdt_disable(wdt_dev);
+ }
+
+ return 0;
+}
+
+static void system_npcx_set_flash_pins_tri_state(const struct device *dev)
+{
+ struct scfg_reg *const inst_scfg = HAL_SCFG_INST(dev);
+
+ inst_scfg->DEVCNT |= BIT(NPCX_DEVCNT_F_SPI_TRIS);
+}
+
+static void system_npcx_init_watchdog_reset(const struct device *dev)
+{
+ struct twd_reg *const inst_twd = HAL_TWD_INST(dev);
+
+ /* Enable early touch */
+ inst_twd->T0CSR &= ~BIT(NPCX_T0CSR_TESDIS);
+ /* watchdog touched by writing 5Ch to WDSDM */
+ inst_twd->TWCFG |= BIT(NPCX_TWCFG_WDSDME);
+}
+
+static void system_npcx_turn_off_adc(void)
+{
+ struct adc_reg *const inst_adc =
+ (struct adc_reg *)(DT_REG_ADDR(DT_INST(0, nuvoton_npcx_adc)));
+
+ inst_adc->ADCCNF = 0;
+ /* Wait for 1000 us to make sure conversion is completed. */
+ k_busy_wait(1000);
+}
+
+static void system_npcx_turn_off_kernel_timer(void)
+{
+ static struct itim32_reg *const evt_tmr =
+ (struct itim32_reg *)DT_REG_ADDR_BY_NAME(
+ DT_INST(0, nuvoton_npcx_itim_timer), evt_itim);
+
+ evt_tmr->ITCTS32 &= ~BIT(NPCX_ITCTSXX_ITEN);
+}
+
+static void system_npcx_disable_instant_wakeup(void)
+{
+ struct pmc_reg *const inst_pmc = (struct pmc_reg *)(DT_REG_ADDR_BY_NAME(
+ DT_INST(0, nuvoton_npcx_pcc), pmc));
+
+ inst_pmc->ENIDL_CTL &= ~BIT(NPCX_ENIDL_CTL_LP_WK_CTL);
+}
+
+static void system_npcx_set_wakeup_gpios_before_hibernate(void)
+{
+ const uintptr_t miwu_base[] = {
+ DT_REG_ADDR(DT_INST(0, nuvoton_npcx_miwu)),
+ DT_REG_ADDR(DT_INST(1, nuvoton_npcx_miwu)),
+ DT_REG_ADDR(DT_INST(2, nuvoton_npcx_miwu)),
+ };
+
+ /* Disable all MIWU inputs before entering hibernate */
+ for (int table = 0; table < ARRAY_SIZE(miwu_base); table++) {
+ for (int group = 0; group < NPCX_MIWU_GROUP_COUNT; group++) {
+ /* Disable all wake-ups */
+ NPCX_WKEN(miwu_base[table], group) = 0x00;
+ /* Clear all pending bits of wake-ups */
+ NPCX_WKPCL(miwu_base[table], group) = 0xFF;
+ /*
+ * Disable all inputs of wake-ups to prevent leakage
+ * caused by input floating.
+ */
+ NPCX_WKINEN(miwu_base[table], group) = 0x00;
+ }
+ }
+
+ static const int wakeup_pin_list[] = {
+#if DT_NODE_EXISTS(SYSTEM_DT_NODE_HIBERNATE_CONFIG)
+ UTIL_LISTIFY(SYSTEM_DT_NODE_WAKEUP_PIN_LEN,
+ SYSTEM_DT_WAKEUP_GPIO_ENUM_BY_IDX, _)
+#endif
+ };
+
+ /* Reconfigure wake-up GPIOs */
+ for (int i = 0; i < ARRAY_SIZE(wakeup_pin_list); i++) {
+ gpio_reset(wakeup_pin_list[i]);
+ /* Re-enable interrupt for wake-up inputs */
+ gpio_enable_interrupt(wakeup_pin_list[i]);
+ }
+}
+
/*
- * For cortex-m we cannot use irq_lock() for disabling all the interrupts
- * because it leaves some (NMI and faults) still enabled. Use "cpsid i" to
- * replace it.
+ * Hibernate function locates in the last 32K ram block in npcx7 series.
+ * Do not use global variables or call functions since we have turned off
+ * the other ram blocks.
*/
-static inline void interrupt_disable_all(void)
+noreturn void __keep __attribute__((section(".lfw.hiber")))
+system_npcx_hibernate_by_lfw_in_last_ram(const struct device *dev,
+ uint32_t pd_ram_mask)
+{
+ /* Modules used for hibernating */
+ struct twd_reg *const inst_twd = HAL_TWD_INST(dev);
+ struct mtc_reg *const inst_mtc = (struct mtc_reg *)(DT_REG_ADDR(
+ DT_INST(0, nuvoton_npcx_cros_mtc)));
+ struct pmc_reg *const inst_pmc = (struct pmc_reg *)(DT_REG_ADDR_BY_NAME(
+ DT_INST(0, nuvoton_npcx_pcc), pmc));
+ uint32_t reset_flags;
+ volatile uint8_t *saved_reset_flags =
+ (volatile uint8_t *)BBRAM_SAVED_RESET_FLAG_ADDR;
+
+ /* Turn off all blocks except last one for better power consumption */
+ inst_pmc->RAM_PD[0] = (uint8_t)pd_ram_mask;
+ inst_pmc->RAM_PD[1] = (uint8_t)(pd_ram_mask >> 8);
+
+ /* Set deep idle mode */
+ inst_pmc->PMCSR = BIT(NPCX_PMCSR_IDLE) | BIT(NPCX_PMCSR_DHF);
+
+ /* Enter system sleep mode */
+ __asm__ volatile("wfi");
+
+ /*
+ * Mark wake-up reason for hibernate. Do not call bbram utilities
+ * directly since the other ram blocks are power down.
+ */
+ if (IS_BIT_SET(inst_mtc->WTC, NPCX_WTC_PTO)) {
+ /* Save wake-up reason as RTC alarm. */
+ reset_flags = EC_RESET_FLAG_RTC_ALARM;
+ } else {
+ /* Otherwise, we treat it as GPIOs wake-up */
+ reset_flags = EC_RESET_FLAG_WAKE_PIN;
+ }
+
+ saved_reset_flags[0] |= reset_flags;
+ saved_reset_flags[1] |= reset_flags >> 8;
+ saved_reset_flags[2] |= reset_flags >> 16;
+ saved_reset_flags[3] |= reset_flags >> 24;
+
+ /*
+ * The trigger of a watchdog event by a "too early service" condition.
+ * When the watchdog is written more than once during three watchdog
+ * clock cycle.
+ */
+ inst_twd->WDSDM = 0x5C;
+ inst_twd->WDSDM = 0x5C;
+
+ /* Spin and wait for reboot; should never return */
+ while (1)
+ continue;
+}
+
+static inline int system_npcx_get_ram_blk_by_lfw_addr(char *address)
{
- __asm__("cpsid i");
+ return NPCX7_RAM_BLOCK_NUM -
+ ceiling_fraction((uint32_t)address -
+ CONFIG_CROS_EC_PROGRAM_MEMORY_BASE,
+ NPCX_RAM_BLOCK_SIZE);
+}
+
+static void system_npcx_hibernate_by_disable_ram(const struct device *dev,
+ uint32_t seconds,
+ uint32_t microseconds)
+{
+ /* Get 32kb ram block order of lfw function */
+ extern char __lfw_text_start[], __lfw_text_end[];
+ int lfw_block = system_npcx_get_ram_blk_by_lfw_addr(__lfw_text_start);
+ uint32_t pd_ram_mask = ~BIT(lfw_block) & NPCX7_RAM_BLOCK_PD_MASK;
+
+ if (lfw_block != system_npcx_get_ram_blk_by_lfw_addr(__lfw_text_end)) {
+ LOG_ERR("LFW cannot cross ram blocks!");
+ return;
+ }
+
+ /*
+ * Set status of pins which connect to flash to tri-state in case
+ * the leakage current.
+ */
+ system_npcx_set_flash_pins_tri_state(dev);
+
+ /* Initialize watchdog for reset after wake-up from hibernating */
+ system_npcx_init_watchdog_reset(dev);
+
+ /* Disable ADC and wait for 1000 us to make sure conversion is done */
+ if (IS_ENABLED(CONFIG_ADC))
+ system_npcx_turn_off_adc();
+
+ /* Disable kernel timer */
+ system_npcx_turn_off_kernel_timer();
+
+ /* Disable instant wake up mode for better power consumption */
+ system_npcx_disable_instant_wakeup();
+
+ /*
+ * Set wake-up input GPIOs and turn off the other sources for better
+ * power consumption before entering hibernate mode.
+ */
+ system_npcx_set_wakeup_gpios_before_hibernate();
+
+ /*
+ * Give the board a chance to do any late stage hibernation work. This
+ * is likely going to configure GPIOs for hibernation. On some boards,
+ * it's possible that this may not return at all. On those boards,
+ * power to the EC is likely being turn off entirely.
+ */
+ if (board_hibernate_late) {
+ board_hibernate_late();
+ }
+
+ /* Setup a RTC alarm if needed */
+ if (IS_ENABLED(CONFIG_RTC) && (seconds || microseconds)) {
+ system_set_rtc_alarm(seconds, microseconds);
+ }
+
+ /* Clear all pending IRQs in case wake-up immediately after sleeping */
+ for (int i = 0; i < CONFIG_NUM_IRQS; i++) {
+ NVIC_ClearPendingIRQ(i);
+ }
+
+ /* Execute hibernate by lfw which locates in last 32K block ram */
+ system_npcx_hibernate_by_lfw_in_last_ram(dev, pd_ram_mask);
}
static const char *cros_system_npcx_get_chip_vendor(const struct device *dev)
@@ -122,6 +400,37 @@ static const char *cros_system_npcx_get_chip_revision(const struct device *dev)
return rev;
}
+static void system_npcx_hibernate_by_psl(const struct device *dev,
+ uint32_t seconds,
+ uint32_t microseconds)
+{
+ ARG_UNUSED(dev);
+ /*
+ * TODO(b/178230662): RTC wake-up in PSL mode only support in npcx9
+ * series. Nuvoton will introduce CLs for it later.
+ */
+ ARG_UNUSED(seconds);
+ ARG_UNUSED(microseconds);
+
+ /*
+ * Configure PSL input pads from "psl-in-pads" property in device tree
+ * file.
+ */
+ npcx_pinctrl_psl_input_configure();
+
+ /*
+ * Give the board a chance to do any late stage hibernation work. This
+ * is likely going to configure GPIOs for hibernation. On some boards,
+ * it's possible that this may not return at all. On those boards,
+ * power to the EC is likely being turn off entirely.
+ */
+ if (board_hibernate_late)
+ board_hibernate_late();
+
+ /* Turn off VCC1 to enter ultra-low-power mode for hibernating */
+ npcx_pinctrl_psl_output_set_inactive();
+}
+
static int cros_system_npcx_get_reset_cause(const struct device *dev)
{
struct cros_system_npcx_data *data = DRV_DATA(dev);
@@ -164,21 +473,10 @@ static int cros_system_npcx_soc_reset(const struct device *dev)
*/
/* Stop the watchdog */
- if (IS_ENABLED(CONFIG_WATCHDOG)) {
- const struct device *wdt_dev = device_get_binding(
- DT_LABEL(DT_INST(0, nuvoton_npcx_watchdog)));
-
- if (!wdt_dev) {
- LOG_ERR("wdt_dev get binding failed");
- return -ENODEV;
- }
+ system_npcx_watchdog_stop();
- wdt_disable(wdt_dev);
- }
-
- /* Enable early touch */
- inst_twd->T0CSR &= ~BIT(NPCX_T0CSR_TESDIS);
- inst_twd->TWCFG |= BIT(NPCX_TWCFG_WDSDME);
+ /* Initialize watchdog for reset */
+ system_npcx_init_watchdog_reset(dev);
/*
* The trigger of a watchdog event by a "too early service" condition.
@@ -200,32 +498,20 @@ static int cros_system_npcx_soc_reset(const struct device *dev)
static int cros_system_npcx_hibernate(const struct device *dev,
uint32_t seconds, uint32_t microseconds)
{
- ARG_UNUSED(seconds);
- ARG_UNUSED(microseconds);
-
/* Disable interrupt first */
interrupt_disable_all();
- /*
- * TODO(b:178230662): RTC wake-up in PSL mode only support in npcx9
- * series. Nuvoton will introduce CLs for it later.
- */
-
- if (IS_ENABLED(CONFIG_PLATFORM_EC_HIBERNATE_PSL)) {
- /*
- * Configure PSL input pads from "psl-in-pads" property in
- * device tree file.
- */
- npcx_pinctrl_psl_input_configure();
+ /* Stop the watchdog */
+ system_npcx_watchdog_stop();
- /* Turn off VCC1 and enter ultra-low-power mode */
- npcx_pinctrl_psl_output_set_inactive();
+ /* Enter hibernate mode */
+ if (IS_ENABLED(CONFIG_PLATFORM_EC_SYSTEM_HIBERNATE_PSL)) {
+ system_npcx_hibernate_by_psl(dev, seconds, microseconds);
+ } else {
+ system_npcx_hibernate_by_disable_ram(dev, seconds,
+ microseconds);
}
- /*
- * TODO(b:183745774): implement Non-PSL hibernate mechanism if
- * CONFIG_PLATFORM_EC_HIBERNATE_PSL is not enabled.
- */
return 0;
}
diff --git a/zephyr/dts/bindings/gpio/gpio-enum-name.yaml b/zephyr/dts/bindings/gpio/gpio-enum-name.yaml
index d30984184d..b63020d4bc 100644
--- a/zephyr/dts/bindings/gpio/gpio-enum-name.yaml
+++ b/zephyr/dts/bindings/gpio/gpio-enum-name.yaml
@@ -40,6 +40,7 @@ properties:
- GPIO_EC_PCH_SYS_PWROK
- GPIO_EC_PCH_WAKE_ODL
- GPIO_EC_PROCHOT_IN_L
+ - GPIO_EC_RST_ODL
- GPIO_EC_WP_L
- GPIO_EN_A_RAILS
- GPIO_EN_PP3300_A
diff --git a/zephyr/dts/bindings/gpio/hibernate-wake-pins.yaml b/zephyr/dts/bindings/gpio/hibernate-wake-pins.yaml
new file mode 100644
index 0000000000..64435f7b3b
--- /dev/null
+++ b/zephyr/dts/bindings/gpio/hibernate-wake-pins.yaml
@@ -0,0 +1,13 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: Hibernate Wake-up Pins Configurations
+
+compatible: "cros-ec,hibernate-wake-pins"
+
+properties:
+ wakeup-pins:
+ type: phandles
+ required: true
+ description: GPIO list for hibernate wake-up
diff --git a/zephyr/linker/CMakeLists.txt b/zephyr/linker/CMakeLists.txt
index 170055dba7..27b028d22c 100644
--- a/zephyr/linker/CMakeLists.txt
+++ b/zephyr/linker/CMakeLists.txt
@@ -10,3 +10,7 @@ zephyr_linker_sources(RWDATA SORT_KEY 1 iram_text.ld)
# Compute the image size
zephyr_linker_sources(RAM_SECTIONS image_size.ld)
+
+# Little FW with specific purposes used by NPCX EC
+zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_NPCX ROM_START SORT_KEY 1
+ npcx-lfw.ld)
diff --git a/zephyr/linker/npcx-lfw.ld b/zephyr/linker/npcx-lfw.ld
new file mode 100644
index 0000000000..bdab9c3546
--- /dev/null
+++ b/zephyr/linker/npcx-lfw.ld
@@ -0,0 +1,10 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+. = ALIGN(4);
+__lfw_text_start = .;
+*(.lfw.*)
+. = ALIGN(4);
+__lfw_text_end = .;
diff --git a/zephyr/projects/trogdor/lazor/gpio.dts b/zephyr/projects/trogdor/lazor/gpio.dts
index c5f95a1fd1..5e91c23d57 100644
--- a/zephyr/projects/trogdor/lazor/gpio.dts
+++ b/zephyr/projects/trogdor/lazor/gpio.dts
@@ -131,6 +131,7 @@
};
ec_rst_odl {
gpios = <&gpio0 2 GPIO_INPUT>;
+ enum-name = "GPIO_EC_RST_ODL";
label = "EC_RST_ODL";
};
ec_entering_rw {
diff --git a/zephyr/shim/src/system.c b/zephyr/shim/src/system.c
index b1a443fbf4..c8b5c81341 100644
--- a/zephyr/shim/src/system.c
+++ b/zephyr/shim/src/system.c
@@ -176,8 +176,7 @@ static int check_reset_cause(void)
/*
* TODO(b/182876692): Implement CONFIG_POWER_BUTTON_INIT_IDLE &
- * CONFIG_BOARD_FORCE_RESET_PIN. Also, check the hibernate flow if PSL
- * merge into tot.
+ * CONFIG_BOARD_FORCE_RESET_PIN.
*/
switch (chip_reset_cause) {
@@ -234,10 +233,11 @@ static int check_reset_cause(void)
case WATCHDOG_RST:
/*
* Don't set EC_RESET_FLAG_WATCHDOG flag if watchdog is issued
- * by system_reset in order to distinguish reset cause is panic
- * reason or not.
+ * by system_reset or hibernate in order to distinguish reset
+ * cause is panic reason or not.
*/
- if (!(system_flags & (EC_RESET_FLAG_SOFT | EC_RESET_FLAG_HARD)))
+ if (!(system_flags & (EC_RESET_FLAG_SOFT | EC_RESET_FLAG_HARD |
+ EC_RESET_FLAG_HIBERNATE)))
system_flags |= EC_RESET_FLAG_WATCHDOG;
break;
}