diff options
-rw-r--r-- | board/npcx7_evb/board.h | 1 | ||||
-rw-r--r-- | board/npcx_evb/board.h | 1 | ||||
-rw-r--r-- | board/npcx_evb_arm/board.h | 1 | ||||
-rw-r--r-- | chip/npcx/build.mk | 2 | ||||
-rw-r--r-- | chip/npcx/lpc.c | 216 | ||||
-rw-r--r-- | chip/npcx/registers.h | 1 | ||||
-rw-r--r-- | chip/npcx/sib.c | 187 | ||||
-rw-r--r-- | chip/npcx/sib_chip.h | 23 | ||||
-rw-r--r-- | chip/npcx/system.c | 23 | ||||
-rw-r--r-- | include/config.h | 9 |
10 files changed, 271 insertions, 193 deletions
diff --git a/board/npcx7_evb/board.h b/board/npcx7_evb/board.h index 7e8afa78d8..cf79888045 100644 --- a/board/npcx7_evb/board.h +++ b/board/npcx7_evb/board.h @@ -20,6 +20,7 @@ /* Optional features */ #define CONFIG_BOARD_VERSION +#define CONFIG_ENABLE_JTAG_SELECTION #define CONFIG_EXTPOWER_GPIO #define CONFIG_I2C_MASTER #define CONFIG_KEYBOARD_BOARD_CONFIG diff --git a/board/npcx_evb/board.h b/board/npcx_evb/board.h index 4ca106bf8c..c29b2d52f3 100644 --- a/board/npcx_evb/board.h +++ b/board/npcx_evb/board.h @@ -29,6 +29,7 @@ #define CONFIG_VBOOT_HASH #define CONFIG_PWM_KBLIGHT #define CONFIG_BOARD_VERSION +#define CONFIG_ENABLE_JTAG_SELECTION /* Optional features for test commands */ #define CONFIG_CMD_TASKREADY diff --git a/board/npcx_evb_arm/board.h b/board/npcx_evb_arm/board.h index dae3af8fb0..ba42cb67e7 100644 --- a/board/npcx_evb_arm/board.h +++ b/board/npcx_evb_arm/board.h @@ -26,6 +26,7 @@ #define CONFIG_VBOOT_HASH #define CONFIG_PWM_KBLIGHT #define CONFIG_BOARD_VERSION +#define CONFIG_ENABLE_JTAG_SELECTION /* Optional features for test commands */ #define CONFIG_CMD_TASKREADY diff --git a/chip/npcx/build.mk b/chip/npcx/build.mk index f228a13de1..37ac54b2ca 100644 --- a/chip/npcx/build.mk +++ b/chip/npcx/build.mk @@ -17,7 +17,7 @@ CHIP_FAMILY:=npcx5 endif # Required chip modules -chip-y=header.o clock.o gpio.o hwtimer.o system.o uart.o +chip-y=header.o clock.o gpio.o hwtimer.o system.o uart.o sib.o chip-y+=system-$(CHIP_FAMILY).o # Optional chip modules diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c index 5b07362bae..5558419dc4 100644 --- a/chip/npcx/lpc.c +++ b/chip/npcx/lpc.c @@ -17,11 +17,10 @@ #include "lpc.h" #include "lpc_chip.h" #include "port80.h" -#include "pwm.h" #include "registers.h" #include "system.h" +#include "sib_chip.h" #include "task.h" -#include "timer.h" #include "uart.h" #include "util.h" #include "system_chip.h" @@ -39,24 +38,6 @@ #define PMC_ACPI PM_CHAN_1 #define PMC_HOST_CMD PM_CHAN_2 -/* Super-IO index and register definitions */ -#define SIO_OFFSET 0x4E -#define INDEX_SID 0x20 -#define INDEX_CHPREV 0x24 -#define INDEX_SRID 0x27 - -/* - * Timeout to wait for host transaction to be completed. - * - * For eSPI - it is 200 us. - * For LPC - it is 5 us. - */ -#ifdef CONFIG_ESPI -#define LPC_HOST_TRANSACTION_TIMEOUT_US 200 -#else -#define LPC_HOST_TRANSACTION_TIMEOUT_US 5 -#endif - static struct host_packet lpc_packet; static struct host_cmd_handler_args host_cmd_args; static uint8_t host_cmd_flags; /* Flags from host command */ @@ -326,75 +307,6 @@ void lpc_keyboard_put_char(uint8_t chr, int send_irq) } } -/* - * Check host read is not in-progress and no timeout - */ -static void lpc_sib_wait_host_read_done(void) -{ - timestamp_t deadline; - - deadline.val = get_time().val + LPC_HOST_TRANSACTION_TIMEOUT_US; - while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) { - if (timestamp_expired(deadline, NULL)) { - ccprintf("Unexpected time of host read transaction\n"); - break; - } - } -} - -/* - * Check host write is not in-progress and no timeout - */ -static void lpc_sib_wait_host_write_done(void) -{ - timestamp_t deadline; - - deadline.val = get_time().val + LPC_HOST_TRANSACTION_TIMEOUT_US; - while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) { - if (timestamp_expired(deadline, NULL)) { - ccprintf("Unexpected time of host write transaction\n"); - break; - } - } -} - -/* Emulate host to read Keyboard I/O */ -uint8_t lpc_sib_read_kbc_reg(uint8_t io_offset) -{ - uint8_t data_value; - - /* Disable interrupts */ - interrupt_disable(); - - /* Lock host keyboard module */ - SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKHIKBD); - /* Verify Core read/write to host modules is not in progress */ - lpc_sib_wait_host_read_done(); - lpc_sib_wait_host_write_done(); - /* Enable Core access to keyboard module */ - SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_HIKBDAE); - - /* Specify the io_offset A0 = 0. the index register is accessed */ - NPCX_IHIOA = io_offset; - - /* Start a Core read from host module */ - SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD); - /* Wait while Core read operation is in progress */ - lpc_sib_wait_host_read_done(); - /* Read the data */ - data_value = NPCX_IHD; - - /* Disable Core access to keyboard module */ - CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_HIKBDAE); - /* unlock host keyboard module */ - CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKHIKBD); - - /* Enable interrupts */ - interrupt_enable(); - - return data_value; -} - void lpc_keyboard_clear_buffer(void) { /* Clear OBF flag in host STATUS and HIKMST regs */ @@ -405,7 +317,7 @@ void lpc_keyboard_clear_buffer(void) * Emulate a host read to clear these two flags and also * deassert IRQ1 */ - lpc_sib_read_kbc_reg(0x0); + sib_read_kbc_reg(0x0); } } @@ -645,86 +557,6 @@ static void lpc_sysjump(void) } DECLARE_HOOK(HOOK_SYSJUMP, lpc_sysjump, HOOK_PRIO_DEFAULT); -/* Super-IO read/write function */ -void lpc_sib_write_reg(uint8_t io_offset, uint8_t index_value, - uint8_t io_data) -{ - /* Disable interrupts */ - interrupt_disable(); - - /* Lock host CFG module */ - SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); - /* Enable Core access to CFG module */ - SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); - /* Verify Core read/write to host modules is not in progress */ - lpc_sib_wait_host_read_done(); - lpc_sib_wait_host_write_done(); - - /* Specify the io_offset A0 = 0. the index register is accessed */ - NPCX_IHIOA = io_offset; - /* Write the data. This starts the write access to the host module */ - NPCX_IHD = index_value; - /* Wait while Core write operation is in progress */ - lpc_sib_wait_host_write_done(); - - /* Specify the io_offset A0 = 1. the data register is accessed */ - NPCX_IHIOA = io_offset+1; - /* Write the data. This starts the write access to the host module */ - NPCX_IHD = io_data; - /* Wait while Core write operation is in progress */ - lpc_sib_wait_host_write_done(); - - /* Disable Core access to CFG module */ - CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); - /* unlock host CFG module */ - CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); - - /* Enable interrupts */ - interrupt_enable(); -} - -uint8_t lpc_sib_read_reg(uint8_t io_offset, uint8_t index_value) -{ - uint8_t data_value; - - /* Disable interrupts */ - interrupt_disable(); - - /* Lock host CFG module */ - SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); - /* Enable Core access to CFG module */ - SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); - /* Verify Core read/write to host modules is not in progress */ - lpc_sib_wait_host_read_done(); - lpc_sib_wait_host_write_done(); - - /* Specify the io_offset A0 = 0. the index register is accessed */ - NPCX_IHIOA = io_offset; - /* Write the data. This starts the write access to the host module */ - NPCX_IHD = index_value; - /* Wait while Core write operation is in progress */ - lpc_sib_wait_host_write_done(); - - /* Specify the io_offset A0 = 1. the data register is accessed */ - NPCX_IHIOA = io_offset+1; - /* Start a Core read from host module */ - SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD); - /* Wait while Core read operation is in progress */ - lpc_sib_wait_host_read_done(); - /* Read the data */ - data_value = NPCX_IHD; - - /* Disable Core access to CFG module */ - CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); - /* unlock host CFG module */ - CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); - - /* Enable interrupts */ - interrupt_enable(); - - return data_value; -} - /* For LPC host register initial via SIB module */ void host_register_init(void) { @@ -732,44 +564,44 @@ void host_register_init(void) SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); /* enable ACPI*/ - lpc_sib_write_reg(SIO_OFFSET, 0x07, 0x11); - lpc_sib_write_reg(SIO_OFFSET, 0x30, 0x01); + sib_write_reg(SIO_OFFSET, 0x07, 0x11); + sib_write_reg(SIO_OFFSET, 0x30, 0x01); /* enable KBC*/ - lpc_sib_write_reg(SIO_OFFSET, 0x07, 0x06); - lpc_sib_write_reg(SIO_OFFSET, 0x30, 0x01); + sib_write_reg(SIO_OFFSET, 0x07, 0x06); + sib_write_reg(SIO_OFFSET, 0x30, 0x01); /* Setting PMC2 */ /* LDN register = 0x12(PMC2) */ - lpc_sib_write_reg(SIO_OFFSET, 0x07, 0x12); + sib_write_reg(SIO_OFFSET, 0x07, 0x12); /* CMD port is 0x200 */ - lpc_sib_write_reg(SIO_OFFSET, 0x60, 0x02); - lpc_sib_write_reg(SIO_OFFSET, 0x61, 0x00); + sib_write_reg(SIO_OFFSET, 0x60, 0x02); + sib_write_reg(SIO_OFFSET, 0x61, 0x00); /* Data port is 0x204 */ - lpc_sib_write_reg(SIO_OFFSET, 0x62, 0x02); - lpc_sib_write_reg(SIO_OFFSET, 0x63, 0x04); + sib_write_reg(SIO_OFFSET, 0x62, 0x02); + sib_write_reg(SIO_OFFSET, 0x63, 0x04); /* enable PMC2 */ - lpc_sib_write_reg(SIO_OFFSET, 0x30, 0x01); + sib_write_reg(SIO_OFFSET, 0x30, 0x01); /* Setting SHM */ /* LDN register = 0x0F(SHM) */ - lpc_sib_write_reg(SIO_OFFSET, 0x07, 0x0F); + sib_write_reg(SIO_OFFSET, 0x07, 0x0F); /* WIN1&2 mapping to IO */ - lpc_sib_write_reg(SIO_OFFSET, 0xF1, - lpc_sib_read_reg(SIO_OFFSET, 0xF1) | 0x30); + sib_write_reg(SIO_OFFSET, 0xF1, + sib_read_reg(SIO_OFFSET, 0xF1) | 0x30); /* Host Command on the IO:0x0800 */ - lpc_sib_write_reg(SIO_OFFSET, 0xF7, 0x00); - lpc_sib_write_reg(SIO_OFFSET, 0xF6, 0x00); - lpc_sib_write_reg(SIO_OFFSET, 0xF5, 0x08); - lpc_sib_write_reg(SIO_OFFSET, 0xF4, 0x00); + sib_write_reg(SIO_OFFSET, 0xF7, 0x00); + sib_write_reg(SIO_OFFSET, 0xF6, 0x00); + sib_write_reg(SIO_OFFSET, 0xF5, 0x08); + sib_write_reg(SIO_OFFSET, 0xF4, 0x00); /* WIN1 as Host Command on the IO:0x0800 */ - lpc_sib_write_reg(SIO_OFFSET, 0xFB, 0x00); - lpc_sib_write_reg(SIO_OFFSET, 0xFA, 0x00); + sib_write_reg(SIO_OFFSET, 0xFB, 0x00); + sib_write_reg(SIO_OFFSET, 0xFA, 0x00); /* WIN2 as MEMMAP on the IO:0x900 */ - lpc_sib_write_reg(SIO_OFFSET, 0xF9, 0x09); - lpc_sib_write_reg(SIO_OFFSET, 0xF8, 0x00); + sib_write_reg(SIO_OFFSET, 0xF9, 0x09); + sib_write_reg(SIO_OFFSET, 0xF8, 0x00); /* enable SHM */ - lpc_sib_write_reg(SIO_OFFSET, 0x30, 0x01); + sib_write_reg(SIO_OFFSET, 0x30, 0x01); CPRINTS("Host settings are done!"); diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h index 42286795c0..3cccfb3333 100644 --- a/chip/npcx/registers.h +++ b/chip/npcx/registers.h @@ -63,6 +63,7 @@ #define DEBUG_CLK 0 #define DEBUG_LPC 0 #define DEBUG_ESPI 0 +#define DEBUG_SIB 0 /* Modules Map */ #define NPCX_ESPI_BASE_ADDR 0x4000A000 diff --git a/chip/npcx/sib.c b/chip/npcx/sib.c new file mode 100644 index 0000000000..791bacaa5f --- /dev/null +++ b/chip/npcx/sib.c @@ -0,0 +1,187 @@ +/* + * Copyright 2019 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. + */ + +/* NPCX-specific SIB module for Chrome EC */ + +#include "console.h" +#include "hwtimer_chip.h" +#include "registers.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +/* + * Timeout to wait for host transaction to be completed. + * + * For eSPI - it is 200 us. + * For LPC - it is 5 us. + */ +#ifdef CONFIG_ESPI +#define HOST_TRANSACTION_TIMEOUT_US 200 +#else +#define HOST_TRANSACTION_TIMEOUT_US 5 +#endif + +/* Console output macros */ +#ifdef DEBUG_SIB +#define CPUTS(outstr) cputs(CC_SYSTEM, outstr) +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) +#else +#define CPUTS(...) +#define CPRINTS(...) +#endif + +/* + * Check host read is not in-progress and no timeout + */ +static void sib_wait_host_read_done(void) +{ + timestamp_t deadline, start; + + start = get_time(); + deadline.val = start.val + HOST_TRANSACTION_TIMEOUT_US; + while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) { + if (timestamp_expired(deadline, NULL)) { + CPRINTS("Unexpected time of host read transaction"); + break; + } + } +} + +/* + * Check host write is not in-progress and no timeout + */ +static void sib_wait_host_write_done(void) +{ + timestamp_t deadline, start; + + start = get_time(); + deadline.val = start.val + HOST_TRANSACTION_TIMEOUT_US; + while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) { + if (timestamp_expired(deadline, NULL)) { + CPRINTS("Unexpected time of host write transaction"); + break; + } + } +} + +/* Emulate host to read Keyboard I/O */ +uint8_t sib_read_kbc_reg(uint8_t io_offset) +{ + uint8_t data_value; + + /* Disable interrupts */ + interrupt_disable(); + + /* Lock host keyboard module */ + SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKHIKBD); + /* Verify Core read/write to host modules is not in progress */ + sib_wait_host_read_done(); + sib_wait_host_write_done(); + /* Enable Core access to keyboard module */ + SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_HIKBDAE); + + /* Specify the io_offset A0 = 0. the index register is accessed */ + NPCX_IHIOA = io_offset; + + /* Start a Core read from host module */ + SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD); + /* Wait while Core read operation is in progress */ + sib_wait_host_read_done(); + /* Read the data */ + data_value = NPCX_IHD; + + /* Disable Core access to keyboard module */ + CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_HIKBDAE); + /* unlock host keyboard module */ + CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKHIKBD); + + /* Enable interrupts */ + interrupt_enable(); + + return data_value; +} + +/* Super-IO read/write function */ +void sib_write_reg(uint8_t io_offset, uint8_t index_value, + uint8_t io_data) +{ + /* Disable interrupts */ + interrupt_disable(); + + /* Lock host CFG module */ + SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); + /* Enable Core access to CFG module */ + SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); + /* Verify Core read/write to host modules is not in progress */ + sib_wait_host_read_done(); + sib_wait_host_write_done(); + + /* Specify the io_offset A0 = 0. the index register is accessed */ + NPCX_IHIOA = io_offset; + /* Write the data. This starts the write access to the host module */ + NPCX_IHD = index_value; + /* Wait while Core write operation is in progress */ + sib_wait_host_write_done(); + + /* Specify the io_offset A0 = 1. the data register is accessed */ + NPCX_IHIOA = io_offset+1; + /* Write the data. This starts the write access to the host module */ + NPCX_IHD = io_data; + /* Wait while Core write operation is in progress */ + sib_wait_host_write_done(); + + /* Disable Core access to CFG module */ + CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); + /* unlock host CFG module */ + CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); + + /* Enable interrupts */ + interrupt_enable(); +} + +uint8_t sib_read_reg(uint8_t io_offset, uint8_t index_value) +{ + uint8_t data_value; + + /* Disable interrupts */ + interrupt_disable(); + + /* Lock host CFG module */ + SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); + /* Enable Core access to CFG module */ + SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); + /* Verify Core read/write to host modules is not in progress */ + sib_wait_host_read_done(); + sib_wait_host_write_done(); + + /* Specify the io_offset A0 = 0. the index register is accessed */ + NPCX_IHIOA = io_offset; + /* Write the data. This starts the write access to the host module */ + NPCX_IHD = index_value; + /* Wait while Core write operation is in progress */ + sib_wait_host_write_done(); + + /* Specify the io_offset A0 = 1. the data register is accessed */ + NPCX_IHIOA = io_offset+1; + /* Start a Core read from host module */ + SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD); + /* Wait while Core read operation is in progress */ + sib_wait_host_read_done(); + /* Read the data */ + data_value = NPCX_IHD; + + /* Disable Core access to CFG module */ + CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); + /* unlock host CFG module */ + CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); + + /* Enable interrupts */ + interrupt_enable(); + + return data_value; +} + diff --git a/chip/npcx/sib_chip.h b/chip/npcx/sib_chip.h new file mode 100644 index 0000000000..2341f219b4 --- /dev/null +++ b/chip/npcx/sib_chip.h @@ -0,0 +1,23 @@ +/* + * Copyright 2019 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. + */ + +/* NPCX-specific SIB module for Chrome EC */ + +/* Super-IO index and register definitions */ +#define INDEX_SID 0x20 +#define INDEX_CHPREV 0x24 +#define INDEX_SRID 0x27 + +#define SIO_OFFSET 0x4E + +/* Super-IO register write function */ +void sib_write_reg(uint8_t io_offset, uint8_t index_value, + uint8_t io_data); +/* Super-IO register read function */ +uint8_t sib_read_reg(uint8_t io_offset, uint8_t index_value); +/* Emulate host to read Keyboard I/O */ +uint8_t sib_read_kbc_reg(uint8_t io_offset); + diff --git a/chip/npcx/system.c b/chip/npcx/system.c index 96879b40e4..fe771c33d9 100644 --- a/chip/npcx/system.c +++ b/chip/npcx/system.c @@ -16,6 +16,7 @@ #include "hwtimer_chip.h" #include "registers.h" #include "rom_chip.h" +#include "sib_chip.h" #include "system.h" #include "system_chip.h" #include "task.h" @@ -654,6 +655,28 @@ void chip_pre_init(void) CLEAR_BIT(NPCX_DEVALT(ALT_GROUP_5), NPCX_DEVALT5_NJEN0_EN); #endif #endif + +#ifndef CONFIG_ENABLE_JTAG_SELECTION + /* + * (b/129908668) + * This is the workaround to disable the JTAG0 which is enabled + * accidentally by a special key combination. + */ + if (!IS_BIT_SET(NPCX_DEVALT(5), NPCX_DEVALT5_NJEN0_EN)) { + int data; + /* Set DEVALT5.nJEN0_EN to disable JTAG0 */ + SET_BIT(NPCX_DEVALT(5), NPCX_DEVALT5_NJEN0_EN); + /* Enable Core-to-Host Modules Access */ + SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); + /* Clear SIOCFD.JEN0_HSL to disable JTAG0 */ + data = sib_read_reg(SIO_OFFSET, 0x2D); + data &= ~0x80; + sib_write_reg(SIO_OFFSET, 0x2D, data); + /* Disable Core-to-Host Modules Access */ + CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); + } +#endif + } void system_pre_init(void) diff --git a/include/config.h b/include/config.h index a32f67f936..2989ee9bde 100644 --- a/include/config.h +++ b/include/config.h @@ -1644,6 +1644,15 @@ /* To define it, if I2C channel C and PECI used at the same time. */ #undef CONFIG_IT83XX_SMCLK2_ON_GPC7 +/* + * If this is not defined, the firmware will revert the JTAG selection + * triggered by the hardware strap pin. + * Un-define this flag by default for all real platforms. see (b/129908668) + * If some boards (Ex:EVB) require JTAG function, they can define it in + * their board.h + */ +#undef CONFIG_ENABLE_JTAG_SELECTION + /*****************************************************************************/ /* Keyboard config */ |