diff --git a/arch/riscv/include/asm/mach-k1matrix/arch.h b/arch/riscv/include/asm/mach-k1matrix/arch.h index 352d3c56..f26865d7 100644 --- a/arch/riscv/include/asm/mach-k1matrix/arch.h +++ b/arch/riscv/include/asm/mach-k1matrix/arch.h @@ -47,8 +47,9 @@ */ #include -#ifdef CONFIG_K1MATRIX_APU #include +#include +#ifdef CONFIG_K1MATRIX_APU #if defined(__ASSEMBLY__) && !defined(__DTS__) && !defined(LINKER_SCRIPT) .macro k1matrix_cpu_smp_init x100_smp_init @@ -59,7 +60,6 @@ #endif #endif #ifdef CONFIG_K1MATRIX_RMU -#include #if defined(__ASSEMBLY__) && !defined(__DTS__) && !defined(LINKER_SCRIPT) .macro k1matrix_cpu_smp_init c910_smp_init diff --git a/arch/riscv/include/asm/mach-k1matrix/espi.h b/arch/riscv/include/asm/mach-k1matrix/espi.h index dcad8cc1..6eb30f13 100644 --- a/arch/riscv/include/asm/mach-k1matrix/espi.h +++ b/arch/riscv/include/asm/mach-k1matrix/espi.h @@ -8,6 +8,8 @@ #define espi_mrst rmu_espi_rst #define espi_srst rmu_espi_rst +#define ESPI_IRQ IRQ_ESPI_CON + #define SPACEMIT_ESPI_BASE __RMU_ESPI_CFG_BASE #define SPACEMIT_ESPI_IO_BASE __RMU_ESPI_IO_BASE #define SPACEMIT_ESPI_FLASH_BASE __RMU_ESPI_FLASH_BASE @@ -25,6 +27,12 @@ #endif #define espi_hw_ctrl_init() k1matrix_espi_init() +#define espi_hw_get_cfg() spacemit_espi_get_cfg() +#define espi_hw_set_cfg(cfgs) spacemit_espi_set_cfg(cfgs) +#define espi_hw_write_cmd(opcode, hlen, hbuf, dlen, dbuf) \ + spacemit_espi_write_cmd(opcode, hlen, hbuf, dlen, dbuf) +#define espi_hw_irq_init() spacemit_espi_irq_init() +#define espi_hw_handle_irq() spacemit_espi_handle_irq() void k1matrix_espi_init(void); diff --git a/drivers/espi/spacemit_espi.c b/drivers/espi/spacemit_espi.c index 2d55c21d..36b7d3b4 100644 --- a/drivers/espi/spacemit_espi.c +++ b/drivers/espi/spacemit_espi.c @@ -43,57 +43,25 @@ #include #include -#ifdef SYS_REALTIME -#define espi_poll_init() spacemit_espi_poll_init() -#define espi_irq_init() do { } while (0) -#else -#define espi_poll_init() do { } while (0) -#define espi_irq_init() spacemit_espi_irq_init() -#endif - -#define MAX_VWIRE_LEN 64 - -static bh_t espi_bh; static void (*rxvw_callback)(int group, uint8_t rxvw_data); static void (*rxoob_callback)(void *buffer, int len); static void *rxoob_buffer; uint32_t spacemit_espi_read32(caddr_t reg) { - con_dbg("spacemit_espi: %016lx\n", reg); - return __raw_readl(reg); + uint32_t val; + + val = __raw_readl(reg); + con_dbg("spacemit_espi: R %016lx=%08x\n", reg, val); + return val; } void spacemit_espi_write32(uint32_t val, caddr_t reg) { - con_dbg("spacemit_espi: %016lx=%08x\n", reg, val); + con_dbg("spacemit_espi: W %016lx=%08x\n", reg, val); __raw_writel(val, reg); } -uint16_t spacemit_espi_read16(caddr_t reg) -{ - con_dbg("spacemit_espi: %016lx\n", reg); - return __raw_readw(reg); -} - -void spacemit_espi_write16(uint16_t val, caddr_t reg) -{ - con_dbg("spacemit_espi: %016lx=%04x\n", reg, val); - __raw_writew(val, reg); -} - -uint8_t spacemit_espi_read8(caddr_t reg) -{ - con_dbg("spacemit_espi: %016lx\n", reg); - return __raw_readb(reg); -} - -void spacemit_espi_write8(uint8_t val, caddr_t reg) -{ - con_dbg("spacemit_espi: %016lx=%02x\n", reg, val); - __raw_writeb(val, reg); -} - static inline void espi_clear_upcmd_status(void) { spacemit_espi_clear32(ESPI_UPCMD_STATUS, ESPI_UP_RXHDR); @@ -274,7 +242,7 @@ static int espi_find_io_window(uint16_t win_base) if (!espi_is_decode_enabled(espi_decode_io_range_en_bit(i))) continue; - if (spacemit_espi_read16(espi_io_range_base_reg(i)) == win_base) + if (spacemit_espi_read32(espi_io_range_base_reg(i)) == win_base) return i; } return -1; @@ -339,13 +307,13 @@ static int espi_std_io_decode(uint16_t base, size_t size) static size_t espi_get_io_window_size(int idx) { - return spacemit_espi_read8(espi_io_range_size_reg(idx)) + 1; + return spacemit_espi_read32(espi_io_range_size_reg(idx)) + 1; } static void espi_write_io_window(int idx, uint16_t base, size_t size) { - spacemit_espi_write16(base, espi_io_range_base_reg(idx)); - spacemit_espi_write8(size - 1, espi_io_range_size_reg(idx)); + spacemit_espi_write32(base, espi_io_range_base_reg(idx)); + spacemit_espi_write32(size - 1, espi_io_range_size_reg(idx)); } static int espi_open_generic_io_window(uint16_t base, size_t size) @@ -430,13 +398,13 @@ static int espi_get_unused_mmio_window(void) static size_t espi_get_mmio_window_size(int idx) { - return spacemit_espi_read16(espi_mmio_range_size_reg(idx)) + 1; + return spacemit_espi_read32(espi_mmio_range_size_reg(idx)) + 1; } static void espi_write_mmio_window(int idx, uint32_t base, size_t size) { spacemit_espi_write32(base, espi_mmio_range_base_reg(idx)); - spacemit_espi_write16(size - 1, espi_mmio_range_size_reg(idx)); + spacemit_espi_write32(size - 1, espi_mmio_range_size_reg(idx)); } int espi_open_mmio_window(uint32_t base, size_t size) @@ -496,16 +464,17 @@ static int espi_configure_decodes(const struct espi_config *cfg) return 0; } #endif + /* Wait up to ESPI_CMD_TIMEOUT_US for hardware to clear DNCMD_STATUS bit. */ static int espi_wait_ready(void) { int count = 1000; do { - if (!spacemit_espi_read_dncmd()) + if (spacemit_espi_write_done()) return 0; } while (count--); - return -1; + return -EAGAIN; } /* Clear interrupt status register */ @@ -577,45 +546,6 @@ static int espi_send_command(const struct espi_cmd *cmd) return 0; } -static int espi_send_reset(void) -{ - struct espi_cmd cmd = { - .hdr0 = { - .cmd_type = ESPI_DNCMD_IN_BAND_RESET, - .cmd_sts = 1, - }, - - /* - * When performing an in-band reset the host controller and the - * peripheral can have mismatched IO configs. - * - * i.e., The eSPI peripheral can be in IO-4 mode while, the - * eSPI host will be in IO-1. This results in the peripheral - * getting invalid packets and thus not responding. - * - * If the peripheral is alerting when we perform an in-band - * reset, there is a race condition in espi_send_command. - * 1) espi_send_command clears the interrupt status. - * 2) eSPI host controller hardware notices the alert and sends - * a GET_STATUS. - * 3) espi_send_command writes the in-band reset command. - * 4) eSPI hardware enqueues the in-band reset until GET_STATUS - * is complete. - * 5) GET_STATUS fails with NO_RESPONSE and sets the interrupt - * status. - * 6) eSPI hardware performs in-band reset. - * 7) espi_send_command checks the status and sees a - * NO_RESPONSE bit. - * - * As a workaround we allow the NO_RESPONSE status code when - * we perform an in-band reset. - */ - .expected_status_codes = ESPI_NO_RSP_INT, - }; - - return espi_send_command(&cmd); -} - static int espi_send_pltrst(bool assert) { struct espi_cmd cmd = { @@ -694,8 +624,7 @@ static int espi_get_general_configuration(uint32_t *config) return 0; } -static int espi_set_general_configuration(const struct espi_config *mb_cfg, - uint32_t slave_caps) +static int espi_set_general_configuration(uint32_t slave_caps) { uint32_t slave_config = 0; uint32_t ctrlr_config = 0; @@ -826,7 +755,7 @@ static int espi_setup_vw_channel(uint32_t slave_caps) if (!espi_slave_vw_chan_sup(slave_caps)) { con_err("espi: VW channel not supported: %x\n", slave_caps); - return -ENOTSUP; +// return -ENOTSUP; } if (espi_get_configuration(SPACEMIT_ESPI_SLAVE_VW_CFG, &slave_vw_caps) != 0) { @@ -905,7 +834,7 @@ static int espi_setup_flash_channel(uint32_t slave_caps) * freq: 16MHz * slect alert mode */ -static void espi_set_initial_config(const struct espi_config *mb_cfg) +static void espi_set_initial_config(void) { uint32_t espi_initial_mode = ESPI_CLK_FREQ_SEL(ESPI_GEN_OP_FREQ_20MHZ) | ESPI_IO_MODE_SEL(ESPI_GEN_IO_MODE_SINGLE); @@ -932,7 +861,7 @@ static void espi_set_initial_config(const struct espi_config *mb_cfg) spacemit_espi_write32(espi_initial_mode, ESPI_SLAVE0_CONFIG); } -static void espi_setup_subtractive_decode(const struct espi_config *mb_cfg) +static void espi_setup_subtractive_decode(uint32_t std_io_decode_bitmap) { // uint32_t global_ctrl_reg; // global_ctrl_reg = spacemit_espi_read32(ESPI_GLOBAL_CONTROL_1); @@ -1027,62 +956,122 @@ int spacemit_espi_rx_oob(uint8_t *buf) return len; } -#ifdef SYS_REALTIME -static void spacemit_espi_poll_init(void) +void spacemit_espi_irq_init(void) { - irq_register_poller(espi_bh); + irqc_configure_irq(ESPI_IRQ, 0, IRQ_LEVEL_TRIGGERED); + irq_register_vector(ESPI_IRQ, espi_handle_irq); + irqc_enable_irq(ESPI_IRQ); + spacemit_espi_enable_all_irqs(); } -#else -static void espi_enable_all_irqs(void) -{ - spacemit_espi_write32(ESPI_ALL_INT, ESPI_SLAVE0_INT_EN); -} - -static void spacemit_espi_irq_init(void) -{ - irqc_configure_irq(100, 0, IRQ_LEVEL_TRIGGERED); - irq_register_vector(100, espi_handle_irq); - irqc_enable_irq(100); - espi_enable_all_irqs(); -} -#endif -void espi_handle_irq(irq_t irq) +void spacemit_espi_handle_irq(void) { int int_sts; int len; uint8_t rxvw_data; - int_sts = spacemit_espi_read32(ESPI_SLAVE0_INT_STS); + int_sts = __raw_readl(ESPI_SLAVE0_INT_STS); + __raw_writel(int_sts, ESPI_SLAVE0_INT_STS); - spacemit_espi_write32(int_sts, ESPI_SLAVE0_INT_STS); - - switch (int_sts) { - case 0: - break; - case ESPI_RXVW_GRP0_INT: - rxvw_data = spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFFU; - rxvw_callback(128, rxvw_data); - break; - case ESPI_RXVW_GRP1_INT: - rxvw_data = (spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFF00U) >> 8; - rxvw_callback(129, rxvw_data); - break; - case ESPI_RXVW_GRP2_INT: - rxvw_data = (spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFF0000U) >> 8; - rxvw_callback(130, rxvw_data); - break; - case ESPI_RXVW_GRP3_INT: - rxvw_data = (spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFF000000U) >> 8; - rxvw_callback(131, rxvw_data); - break; - case ESPI_RXOOB_INT: + if (int_sts & ESPI_FLASH_REQ_INT) + con_log("spacemit_espi: ESPI_FLASH_REQ_INT\n"); + if (int_sts & ESPI_RXOOB_INT) { + con_log("spacemit_espi: ESPI_RXOOB_INT\n"); len = spacemit_espi_rx_oob((uint8_t *)rxoob_buffer); rxoob_callback(rxoob_buffer, len); - default: - con_err("espi: Unknown IRQ %d\n", int_sts); - break; } + if (int_sts & ESPI_RXMSG_INT) + con_log("spacemit_espi: ESPI_RXMSG_INT\n"); + if (int_sts & ESPI_DNCMD_INT) { + con_log("spacemit_espi: ESPI_DNCMD_INT\n"); + espi_cmd_complete(0); + } + if (int_sts & ESPI_RXVW_GRP3_INT) { + con_log("spacemit_espi: ESPI_RXVW_GRP3_INT\n"); + rxvw_data = (spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFF000000U) >> 8; + rxvw_callback(131, rxvw_data); + } + if (int_sts & ESPI_RXVW_GRP2_INT) { + con_log("spacemit_espi: ESPI_RXVW_GRP2_INT\n"); + rxvw_data = (spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFF0000U) >> 8; + rxvw_callback(130, rxvw_data); + } + if (int_sts & ESPI_RXVW_GRP1_INT) { + con_log("spacemit_espi: ESPI_RXVW_GRP1_INT\n"); + rxvw_data = (spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFF00U) >> 8; + rxvw_callback(129, rxvw_data); + } + if (int_sts & ESPI_RXVW_GRP0_INT) { + con_log("spacemit_espi: ESPI_RXVW_GRP0_INT\n"); + rxvw_data = spacemit_espi_read32(ESPI_SLAVE0_RXVW_DATA) & 0xFFU; + rxvw_callback(128, rxvw_data); + } + if (int_sts & ESPI_PR_INT) + con_log("spacemit_espi: ESPI_PR_INT\n"); + if (int_sts & ESPI_PROTOCOL_ERR_INT) + con_log("spacemit_espi: ESPI_PROTOCOL_ERR_INT\n"); + if (int_sts & ESPI_RXFLASH_OFLOW_INT) + con_log("spacemit_espi: ESPI_RXFLASH_OFLOW_INT\n"); + if (int_sts & ESPI_RXMSG_OFLOW_INT) + con_log("spacemit_espi: ESPI_RXMSG_OFLOW_INT\n"); + if (int_sts & ESPI_RXOOB_OFLOW_INT) + con_log("spacemit_espi: ESPI_RXOOB_OFLOW_INT\n"); + if (int_sts & ESPI_ILLEGAL_LEN_INT) + con_log("spacemit_espi: ESPI_ILLEGAL_LEN_INT\n"); + if (int_sts & ESPI_ILLEGAL_TAG_INT) + con_log("spacemit_espi: ESPI_ILLEGAL_TAG_INT\n"); + if (int_sts & ESPI_UNSUCSS_CPL_INT) + con_log("spacemit_espi: ESPI_UNSUCSS_CPL_INT\n"); + if (int_sts & ESPI_INVALID_CT_RSP_INT) + con_log("spacemit_espi: ESPI_INVALID_CP_RSP_INT\n"); + if (int_sts & ESPI_INVALID_ID_RSP_INT) + con_log("spacemit_espi: ESPI_INVALID_ID_RSP_INT\n"); + if (int_sts & ESPI_NON_FATAL_INT) + con_log("spacemit_espi: ESPI_NON_FATAL_INT\n"); + if (int_sts & ESPI_FATAL_ERR_INT) + con_log("spacemit_espi: ESPI_FATAL_ERR_INT\n"); + if (int_sts & ESPI_NO_RSP_INT) { + /* When performing an in-band reset the host controller + * and the peripheral can have mismatched IO configs. + * + * i.e., The eSPI peripheral can be in IO-4 mode while, the + * eSPI host will be in IO-1. This results in the + * peripheral getting invalid packets and thus not + * responding. + * + * If the peripheral is alerting when we perform an in-band + * reset, there is a race condition in + * spacemit_espi_write_cmd(). + * 1) spacemit_espi_write_cmd() clears the interrupt + * status. + * 2) eSPI host controller hardware notices the alert and + * sends a GET_STATUS. + * 3) spacemit_espi_write_cmd() writes the in-band reset + * command. + * 4) eSPI hardware enqueues the in-band reset until + * GET_STATUS is complete. + * 5) GET_STATUS fails with NO_RSP_INT and sets the + * interrupt status. + * 6) eSPI hardware performs in-band reset. + * 7) spacemit_espi_write_cmd() checks the status and sees + * a NO_RSP_INT bit. + * + * As a workaround we allow the NO_RSP_INT status code + * when we perform an in-band reset. + */ + con_log("spacemit_espi: ESPI_NO_RSP_INT\n"); + } + if (int_sts & ESPI_CRC_ERR_INT) + con_log("spacemit_espi: ESPI_CRC_ERR_INT\n"); + if (int_sts & ESPI_WAIT_TIMEOUT_INT) + con_log("spacemit_espi: ESPI_WAIT_TIMEOUT_INT\n"); + if (int_sts & ESPI_BUS_ERR_INT) + con_log("spacemit_espi: ESPI_BUS_ERR_INT\n"); +} + +void espi_handle_irq(irq_t irq) +{ + spacemit_espi_handle_irq(); } void espi_register_rxvw_callback(void *callback) @@ -1096,33 +1085,97 @@ void espi_register_rxoob_callbcak(void *callback, void *buffer) rxoob_buffer = buffer; } -struct espi_config def_cfg; - -static void espi_bh_handler(uint8_t event) +void spacemit_espi_write_cmd_async(uint8_t opcode, + uint8_t hlen, uint8_t *hbuf, + uint8_t dlen, uint8_t *dbuf) { - espi_handle_irq(0); + uint8_t i; + uint8_t dncmd; + uint32_t txdata; + uint8_t db0, db1, db2, db3; + + switch (opcode) { + case ESPI_CMD_SET_CONFIGURATION: + dncmd = ESPI_DNCMD_SET_CONFIGURATION; + break; + case ESPI_CMD_GET_CONFIGURATION: + dncmd = ESPI_DNCMD_GET_CONFIGURATION; + break; + case ESPI_CMD_RESET: + default: + dncmd = ESPI_DNCMD_IN_BAND_RESET; + break; + } + + con_dbg("spacemit_espi: cmd: %02x, hdr=%d, dat=%d\n", dncmd, hlen, dlen); + + for (i = 0; i < hlen; i++) + spacemit_espi_write_txhdr(i, hbuf[i]); + for (i = 0; i < ((dlen + 3) / 4); i++) { + uint8_t ilen = i * 4; + + if (ilen < dlen) + db0 = dbuf[ilen]; + else + db0 = 0x00; + if ((ilen + 1) < dlen) + db1 = dbuf[ilen + 1]; + else + db1 = 0x00; + if ((ilen + 2) < dlen) + db2 = dbuf[ilen + 2]; + else + db2 = 0x00; + if ((ilen + 3) < dlen) + db3 = dbuf[ilen + 3]; + else + db3 = 0x00; + txdata = MAKELONG(MAKEWORD(db0, db1), + MAKEWORD(db2, db3)); + spacemit_espi_write32(txdata, ESPI_DN_TXDATA_PORT); + } + spacemit_espi_write_dncmd(dncmd, 0); } -int espi_bh_create(void) +int spacemit_espi_write_complete(void) { - espi_bh = bh_register_handler(espi_bh_handler); - espi_irq_init(); - espi_poll_init(); + while (!spacemit_espi_write_done()); return 0; } -void spacemit_espi_init(void) +int spacemit_espi_write_cmd(uint8_t opcode, + uint8_t hlen, uint8_t *hbuf, + uint8_t dlen, uint8_t *dbuf) { - uint32_t slave_caps; - struct espi_config *cfg; + if (!spacemit_espi_write_done()) + return -EAGAIN; - con_log("Initializing eSPI.\n"); + espi_raise_event(ESPI_EVENT_WAIT_CMD); + spacemit_espi_write_cmd_async(opcode, hlen, hbuf, dlen, dbuf); + espi_sync(); +} - def_cfg.std_io_decode_bitmap = ESPI_DECODE_IO_0x80_EN | ESPI_DECODE_IO_0X2E_0X2F_EN | ESPI_DECODE_IO_0X60_0X64_EN; - cfg = &def_cfg; +#ifdef CONFIG_SPACEMIT_ESPI_AUTO_GATING +void spacemit_espi_config_gating(void) +{ + spacemit_espi_clear32(ESPI_MST_STOP_EN, ESPI_GLOBAL_CONTROL_0); +} +#else +#define spacemit_espi_config_gating() do { } while (0) +#endif + +void spacemit_espi_init(void) +{ + con_dbg("spacemit_espi: initializing...\n"); + spacemit_espi_config_gating(); + spacemit_espi_reset(); +} + +#if 0 +void spacemit_espi_test(void) +{ + uint32_t slave_caps; - spacemit_espi_set32(ESPI_MST_STOP_EN, ESPI_GLOBAL_CONTROL_0); - spacemit_espi_set32(ESPI_ESPI_RSTN, ESPI_GLOBAL_CONTROL_1); // spacemit_espi_write32(ESPI_RGCMD_INT(23) | ESPI_ERR_INT_SMI, ESPI_GLOBAL_CONTROL_1); spacemit_espi_write32(0, ESPI_SLAVE0_INT_EN); espi_clear_status(); @@ -1132,20 +1185,16 @@ void spacemit_espi_init(void) * Set correct initial configuration to talk to the slave: * Set clock frequency to 16.7MHz and single IO mode. */ - espi_set_initial_config(cfg); + espi_set_initial_config(); /* Boot sequence: Step 2 * Send in-band reset * The resets affects both host and slave devices, so set initial * config again. */ - if (espi_send_reset() != 0) { - con_err("In-band reset failed!\n"); - return; - } con_log("In-band reset success!\n"); - espi_set_initial_config(cfg); + espi_set_initial_config(); /* Boot sequence: Step 3 * Get configuration of slave device. @@ -1160,7 +1209,7 @@ void spacemit_espi_init(void) * Step 4: Write slave device general config * Step 5: Set host slave config */ - if (espi_set_general_configuration(cfg, slave_caps) != 0) { + if (espi_set_general_configuration(slave_caps) != 0) { con_err("Slave SET_CONFIGURATION failed!\n"); return; } @@ -1169,7 +1218,7 @@ void spacemit_espi_init(void) /* Setup polarity before enabling the VW channel so any interrupts * received will have the correct polarity. */ - spacemit_espi_write32(cfg->vw_irq_polarity, ESPI_SLAVE0_VW_POLARITY); + spacemit_espi_write32(0, ESPI_SLAVE0_VW_POLARITY); /* Boot Sequences: Steps 6 - 9 * Channel setup @@ -1215,7 +1264,9 @@ void spacemit_espi_init(void) // con_err("Configuring decodes success!\n"); /* Enable subtractive decode if configured */ - espi_setup_subtractive_decode(cfg); + espi_setup_subtractive_decode(ESPI_DECODE_IO_0x80_EN | + ESPI_DECODE_IO_0X2E_0X2F_EN | + ESPI_DECODE_IO_0X60_0X64_EN); // ctrl = spacemit_espi_read32(ESPI_GLOBAL_CONTROL_1); // ctrl |= ESPI_BUS_MASTER_EN; @@ -1224,7 +1275,6 @@ void spacemit_espi_init(void) // spacemit_espi_write32(ctrl, ESPI_GLOBAL_CONTROL_1); - espi_bh_create(); #if 0 clk_set_frequency(espi_sclk, ESPI_OP_FREQ_66_MHZ); @@ -1233,6 +1283,8 @@ void spacemit_espi_init(void) con_log("espi: initialized spacemit_espi.\n"); } +#endif + #if 0 static int do_espi_read(int argc, char *argv[]) { @@ -1347,4 +1399,4 @@ DEFINE_COMMAND(espi, do_espi, "SpacemiT enhanced SPI commands", " -eSPI write sequence\n" ); -#endif \ No newline at end of file +#endif diff --git a/include/driver/spacemit_espi.h b/include/driver/spacemit_espi.h index 271c1e8c..880bfce8 100644 --- a/include/driver/spacemit_espi.h +++ b/include/driver/spacemit_espi.h @@ -225,7 +225,7 @@ #define ESPI_RXVW_GRP2_INT _BV(26) #define ESPI_RXVW_GRP1_INT _BV(25) #define ESPI_RXVW_GRP0_INT _BV(24) -#define ESPI_PR_INT_EN _BV(23) +#define ESPI_PR_INT _BV(23) #define ESPI_PROTOCOL_ERR_INT _BV(15) #define ESPI_RXFLASH_OFLOW_INT _BV(14) #define ESPI_RXMSG_OFLOW_INT _BV(13) @@ -246,11 +246,11 @@ ESPI_RXOOB_INT | \ ESPI_RXMSG_INT | \ ESPI_DNCMD_INT | \ - ESPI_RXVW_GPR3_INT | \ - ESPI_RXVW_GPR2_INT | \ - ESPI_RXVW_GPR1_INT | \ - ESPI_RXVW_GPR0_INT | \ - ESPI_PR_INT_EN | \ + ESPI_RXVW_GRP3_INT | \ + ESPI_RXVW_GRP2_INT | \ + ESPI_RXVW_GRP1_INT | \ + ESPI_RXVW_GRP0_INT | \ + ESPI_PR_INT | \ ESPI_PROTOCOL_ERR_INT | \ ESPI_RXFLASH_OFLOW_INT | \ ESPI_RXMSG_OFLOW_INT | \ @@ -298,30 +298,7 @@ /* SLAVE0_RXVW_STS */ #define SLAVE0_RXVW_STS_SYS_EVT_STS _BV(29) -#define SLAVE0_RXVW_STS_IRQ23_STS _BV(23) -#define SLAVE0_RXVW_STS_IRQ22_STS _BV(22) -#define SLAVE0_RXVW_STS_IRQ21_STS _BV(21) -#define SLAVE0_RXVW_STS_IRQ20_STS _BV(20) -#define SLAVE0_RXVW_STS_IRQ19_STS _BV(19) -#define SLAVE0_RXVW_STS_IRQ18_STS _BV(18) -#define SLAVE0_RXVW_STS_IRQ17_STS _BV(17) -#define SLAVE0_RXVW_STS_IRQ16_STS _BV(16) -#define SLAVE0_RXVW_STS_IRQ15_STS _BV(15) -#define SLAVE0_RXVW_STS_IRQ14_STS _BV(14) -#define SLAVE0_RXVW_STS_IRQ13_STS _BV(13) -#define SLAVE0_RXVW_STS_IRQ12_STS _BV(12) -#define SLAVE0_RXVW_STS_IRQ11_STS _BV(11) -#define SLAVE0_RXVW_STS_IRQ10_STS _BV(10) -#define SLAVE0_RXVW_STS_IRQ9_STS _BV(9) -#define SLAVE0_RXVW_STS_IRQ8_STS _BV(8) -#define SLAVE0_RXVW_STS_IRQ7_STS _BV(7) -#define SLAVE0_RXVW_STS_IRQ6_STS _BV(6) -#define SLAVE0_RXVW_STS_IRQ5_STS _BV(5) -#define SLAVE0_RXVW_STS_IRQ4_STS _BV(4) -#define SLAVE0_RXVW_STS_IRQ3_STS _BV(3) -#define SLAVE0_RXVW_STS_IRQ2_STS _BV(2) -#define SLAVE0_RXVW_STS_IRQ1_STS _BV(1) -#define SLAVE0_RXVW_STS_IRQ0_STS _BV(0) +#define SLAVE0_RXVW_STS_IRQ_STS(n) _BV(n) /* SLAVE0_RXVW */ #define SLAVE0_RXVW_HOST_RST_ACK _BV(19) @@ -367,56 +344,10 @@ #define SLAVE0_RXVW_INDEX_GRP0(n) _SET_FV(SLAVE0_RXVW_INDEX_GRP0, n) /* SLAVE0_VW_CTL */ -#define SLAVE0_VW_CTL_IRQ23_MASK _BV(23) -#define SLAVE0_VW_CTL_IRQ22_MASK _BV(22) -#define SLAVE0_VW_CTL_IRQ21_MASK _BV(21) -#define SLAVE0_VW_CTL_IRQ20_MASK _BV(20) -#define SLAVE0_VW_CTL_IRQ19_MASK _BV(19) -#define SLAVE0_VW_CTL_IRQ18_MASK _BV(18) -#define SLAVE0_VW_CTL_IRQ17_MASK _BV(17) -#define SLAVE0_VW_CTL_IRQ16_MASK _BV(16) -#define SLAVE0_VW_CTL_IRQ15_MASK _BV(15) -#define SLAVE0_VW_CTL_IRQ14_MASK _BV(14) -#define SLAVE0_VW_CTL_IRQ13_MASK _BV(13) -#define SLAVE0_VW_CTL_IRQ12_MASK _BV(12) -#define SLAVE0_VW_CTL_IRQ11_MASK _BV(11) -#define SLAVE0_VW_CTL_IRQ10_MASK _BV(10) -#define SLAVE0_VW_CTL_IRQ9_MASK _BV(9) -#define SLAVE0_VW_CTL_IRQ8_MASK _BV(8) -#define SLAVE0_VW_CTL_IRQ7_MASK _BV(7) -#define SLAVE0_VW_CTL_IRQ6_MASK _BV(6) -#define SLAVE0_VW_CTL_IRQ5_MASK _BV(5) -#define SLAVE0_VW_CTL_IRQ4_MASK _BV(4) -#define SLAVE0_VW_CTL_IRQ3_MASK _BV(3) -#define SLAVE0_VW_CTL_IRQ2_MASK _BV(2) -#define SLAVE0_VW_CTL_IRQ1_MASK _BV(1) -#define SLAVE0_VW_CTL_IRQ0_MASK _BV(0) +#define SLAVE0_VW_CTL_IRQ_MASK(n) _BV(n) /* SLAVE0_VW_POLARITY */ -#define SLAVE0_VW_POLARITY_IRQ23_POLARITY _BV(23) -#define SLAVE0_VW_POLARITY_IRQ22_POLARITY _BV(22) -#define SLAVE0_VW_POLARITY_IRQ21_POLARITY _BV(21) -#define SLAVE0_VW_POLARITY_IRQ20_POLARITY _BV(20) -#define SLAVE0_VW_POLARITY_IRQ19_POLARITY _BV(19) -#define SLAVE0_VW_POLARITY_IRQ18_POLARITY _BV(18) -#define SLAVE0_VW_POLARITY_IRQ17_POLARITY _BV(17) -#define SLAVE0_VW_POLARITY_IRQ16_POLARITY _BV(16) -#define SLAVE0_VW_POLARITY_IRQ15_POLARITY _BV(15) -#define SLAVE0_VW_POLARITY_IRQ14_POLARITY _BV(14) -#define SLAVE0_VW_POLARITY_IRQ13_POLARITY _BV(13) -#define SLAVE0_VW_POLARITY_IRQ12_POLARITY _BV(12) -#define SLAVE0_VW_POLARITY_IRQ11_POLARITY _BV(11) -#define SLAVE0_VW_POLARITY_IRQ10_POLARITY _BV(10) -#define SLAVE0_VW_POLARITY_IRQ9_POLARITY _BV(9) -#define SLAVE0_VW_POLARITY_IRQ8_POLARITY _BV(8) -#define SLAVE0_VW_POLARITY_IRQ7_POLARITY _BV(7) -#define SLAVE0_VW_POLARITY_IRQ6_POLARITY _BV(6) -#define SLAVE0_VW_POLARITY_IRQ5_POLARITY _BV(5) -#define SLAVE0_VW_POLARITY_IRQ4_POLARITY _BV(4) -#define SLAVE0_VW_POLARITY_IRQ3_POLARITY _BV(3) -#define SLAVE0_VW_POLARITY_IRQ2_POLARITY _BV(2) -#define SLAVE0_VW_POLARITY_IRQ1_POLARITY _BV(1) -#define SLAVE0_VW_POLARITY_IRQ0_POLARITY _BV(0) +#define SLAVE0_VW_POLARITY_IRQ_POLARITY(n) _BV(n) #define ESPI_DECODE_RANGES_PER_REG_GROUP 4 @@ -511,50 +442,8 @@ struct espi_config { uint32_t vw_irq_polarity; }; -uint8_t spacemit_espi_read8(caddr_t reg); -uint16_t spacemit_espi_read16(caddr_t reg); uint32_t spacemit_espi_read32(caddr_t reg); -void spacemit_espi_write8(uint8_t val, caddr_t reg); -void spacemit_espi_write16(uint16_t val, caddr_t reg); void spacemit_espi_write32(uint32_t val, caddr_t reg); -#define spacemit_espi_set8(v,a) \ - do { \ - uint8_t __v = spacemit_espi_read8(a); \ - __v |= (v); \ - spacemit_espi_write8(__v, (a)); \ - } while (0) -#define spacemit_espi_clear8(v,a) \ - do { \ - uint8_t __v = spacemit_espi_read8(a); \ - __v &= ~(v); \ - spacemit_espi_write8(__v, (a)); \ - } while (0) -#define spacemit_espi_write8_mask(v,m,a) \ - do { \ - uint8_t __v = spacemit_espi_read8(a); \ - __v &= ~(m); \ - __v |= (v); \ - spacemit_espi_write8(__v, (a)); \ - } while (0) -#define spacemit_espi_set16(v,a) \ - do { \ - uint16_t __v = spacemit_espi_read16(a); \ - __v |= (v); \ - spacemit_espi_write16(__v, (a)); \ - } while (0) -#define spacemit_espi_clear16(v,a) \ - do { \ - uint16_t __v = spacemit_espi_read16(a); \ - __v &= ~(v); \ - spacemit_espi_write16(__v, (a)); \ - } while (0) -#define spacemit_espi_write16_mask(v,m,a) \ - do { \ - uint16_t __v = spacemit_espi_read16(a); \ - __v &= ~(m); \ - __v |= (v); \ - spacemit_espi_write16(__v, (a)); \ - } while (0) #define spacemit_espi_set32(v,a) \ do { \ uint32_t __v = spacemit_espi_read32(a); \ @@ -583,25 +472,42 @@ void spacemit_espi_write32(uint32_t val, caddr_t reg); #define ESPI_DNCMD_TYPE_MASK REG_3BIT_MASK #define ESPI_DNCMD_TYPE(value) _SET_FV(ESPI_DNCMD_TYPE, value) #define spacemit_espi_write_dncmd(type, slave) \ - __raw_writel_mask(ESPI_DNCMD_TYPE(type) | \ - ESPI_DNCMD_EN | \ - ESPI_DNCMD_SLAVE_SEL(slave), \ - ESPI_DNCMD_TYPE(ESPI_DNCMD_TYPE_MASK) | \ - ESPI_DNCMD_EN | \ - ESPI_DNCMD_SLAVE_SEL(ESPI_DNCMD_SLAVE_SEL_MASK), \ - ESPI_DN_TXHDR) -#define spacemit_espi_read_dncmd() \ - (__raw_readl(ESPI_DN_TXHDR) & ESPI_DNCMD_EN) + spacemit_espi_write32_mask(ESPI_DNCMD_TYPE(type) | \ + ESPI_DNCMD_EN | ESPI_DNCMD_SLAVE_SEL(slave), \ + ESPI_DNCMD_TYPE(ESPI_DNCMD_TYPE_MASK) | ESPI_DNCMD_EN | \ + ESPI_DNCMD_SLAVE_SEL(ESPI_DNCMD_SLAVE_SEL_MASK), \ + ESPI_DN_TXHDR) #define spacemit_espi_write_txhdr(n, byte) \ - __raw_writel_mask(ESPI_DNCMD_HDATA(n, byte), \ - ESPI_DNCMD_HDATA(n, REG_8BIT_MASK), \ - ESPI_DN_TXHDRn(n)) + spacemit_espi_write32_mask(ESPI_DNCMD_HDATA(n, byte), \ + ESPI_DNCMD_HDATA(n, REG_8BIT_MASK), \ + ESPI_DN_TXHDRn(n)) +#define spacemit_espi_write_done() \ + (!(spacemit_espi_read32(ESPI_DN_TXHDR) & ESPI_DNCMD_EN)) #define spacemit_espi_read_rxhdr(n) \ ((uint8_t)ESPI_UPCMD_HDATA(n, __raw_readl(ESPI_UP_RXHDRn(n)))) #define espi_setup_pr_mem_base0(base) \ spacemit_espi_write32(base, ESPI_PR_BASE_ADDR_MEM0) #define espi_setup_pr_mem_base1(base) \ spacemit_espi_write32(base, ESPI_PR_BASE_ADDR_MEM1) +#define spacemit_espi_enable_all_irqs() \ + spacemit_espi_write32(ESPI_ALL_INT, ESPI_SLAVE0_INT_EN) + +#define spacemit_espi_reset() \ + do { \ + spacemit_espi_clear32(ESPI_ESPI_RSTN, \ + ESPI_GLOBAL_CONTROL_1); \ + spacemit_espi_set32(ESPI_ESPI_RSTN, \ + ESPI_GLOBAL_CONTROL_1); \ + } while (0) + +void spacemit_espi_irq_init(void); +void spacemit_espi_handle_irq(void); +void spacemit_espi_write_cmd_async(uint8_t cmd, + uint8_t hlen, uint8_t *hbuf, + uint8_t dlen, uint8_t *dbuf); +int spacemit_espi_write_cmd(uint8_t cmd, + uint8_t hdr_len, uint8_t *hdr, + uint8_t dat_len, uint8_t *dat); int espi_open_io_window(uint16_t base, size_t size); int espi_open_mmio_window(uint32_t base, size_t size); diff --git a/include/target/espi.h b/include/target/espi.h index 8b328e63..c478a85d 100644 --- a/include/target/espi.h +++ b/include/target/espi.h @@ -3,6 +3,10 @@ #include +/* No commands */ +#define ESPI_CMD_NONE 0xffff +#define ESPI_CMD(cmd) (HIBYTE(cmd) == 0xff ? ESPI_CMD_NONE : LOBYTE(cmd)) + /* eSPI Interface Base Specification - Document # 327432-004 Revision 1.0 */ /* 4.2 Command phase */ #define ESPI_CMD_PUT_PC 0x00 @@ -421,8 +425,47 @@ struct espi_cmd { #define ESPI_ALL_CHAN \ (ESPI_PERI_CHAN | ESPI_VW_CHAN | ESPI_OOB_CHAN | ESPI_FLASH_CHAN) +#define MAX_VWIRE_LEN 64 + +typedef uint16_t espi_event_t; +typedef uint8_t espi_slave_t; +typedef uint8_t espi_op_t; +typedef void (*espi_cmpl_cb)(espi_slave_t slave, uint8_t op, bool result); + +#define ESPI_STATE_INIT 0x00 +#define ESPI_STATE_CONFIG 0x01 + +#define ESPI_EVENT_SETUP 0x01 +#define ESPI_EVENT_RESET 0x02 +#define ESPI_EVENT_WAIT_CMD 0x03 + +#define ESPI_OP_NONE 0x00 +#define ESPI_OP_SETUP_SLAVE 0x01 + +#define espi_op_busy() (!!(espi_op != ESPI_OP_NONE)) +#define espi_op_is(op) (espi_op == (op)) +#define espi_cmd_is(cmd) (ESPI_CMD(espi_cmd) == (cmd)) +#define espi_setup_slave() espi_start_op(ESPI_OP_SETUP_SLAVE, NULL) + #include +int espi_start_op(espi_op_t op, espi_cmpl_cb cb); +void espi_cmd_complete(uint8_t status); +void espi_enter_state(uint8_t state); +void espi_raise_event(espi_event_t event); +void espi_clear_event(espi_event_t event); +espi_event_t espi_event_save(void); +void espi_event_restore(espi_event_t event); +void espi_sync(void); +void espi_seq_handler(void); + +#define espi_inband_reset() \ + espi_write_cmd(ESPI_CMD_RESET, 0, NULL, 0, NULL) + +extern uint8_t espi_op; + +void espi_write_cmd(uint8_t opcode, uint8_t hlen, uint8_t *hbuf, + uint8_t dlen, uint8_t *dbuf); void espi_config_alert_pin(uint32_t slave_caps, uint32_t *slave_config, uint32_t *ctrlr_config); void espi_config_io_mode(uint32_t slave_caps, uint32_t *slave_config, uint32_t *ctrlr_config); void espi_config_op_freq(uint32_t slave_caps, uint32_t *slave_config, uint32_t *ctrlr_config); diff --git a/kernel/ipmi/espi.c b/kernel/ipmi/espi.c index cc20ffe7..13e694db 100644 --- a/kernel/ipmi/espi.c +++ b/kernel/ipmi/espi.c @@ -1,5 +1,60 @@ #include #include +#include + +#ifdef SYS_REALTIME +#define espi_poll_init() __espi_poll_init() +#define espi_irq_init() do { } while (0) +#else +#define espi_poll_init() do { } while (0) +#define espi_irq_init() __espi_irq_init() +#endif + +static bh_t espi_bh; +uint8_t espi_state; +espi_event_t espi_event; +espi_op_t espi_op; +espi_cmpl_cb espi_op_cb; +uint16_t espi_cmd; + +void espi_enter_state(uint8_t state) +{ + espi_state = state; + espi_seq_handler(); +} + +void espi_raise_event(espi_event_t event) +{ + espi_event |= event; + bh_resume(espi_bh); +} + +void espi_clear_event(espi_event_t event) +{ + espi_event &= ~event; +} + +espi_event_t espi_event_save(void) +{ + espi_event_t events; + events = espi_event; + espi_event = 0; + return events; +} + +void espi_event_restore(espi_event_t event) +{ + espi_event |= event; +} + +void espi_sync(void) +{ + do { + bh_sync(); + if (espi_event) + bh_resume(espi_bh); + } while (espi_event); +} void espi_config_alert_pin(uint32_t slave_caps, uint32_t *slave_config, uint32_t *ctrlr_config) { @@ -93,7 +148,93 @@ void espi_config_op_freq(uint32_t slave_caps, uint32_t *slave_config, uint32_t * } } +int espi_start_op(espi_op_t op, espi_cmpl_cb cb) +{ + if (espi_op_busy()) + return -EBUSY; + + espi_op = op; + espi_op_cb = cb; + espi_seq_handler(); + return 0; +} + +void espi_cmd_complete(uint8_t status) +{ + espi_clear_event(ESPI_EVENT_WAIT_CMD); +} + +void espi_handle_setup_slave(bool is_op) +{ + if (espi_state == ESPI_STATE_INIT) { + espi_inband_reset(); + } +} + +void espi_seq_handler(void) +{ + if (espi_op_is(ESPI_OP_SETUP_SLAVE)) + espi_handle_setup_slave(true); +} + +static void espi_async_handler(void) +{ + espi_event_t flags; + + flags = espi_event_save(); + if (flags & ESPI_EVENT_SETUP) { + espi_setup_slave(); + unraise_bits(flags, ESPI_EVENT_SETUP); + } + espi_event_restore(flags); +} + +static void espi_bh_handler(uint8_t events) +{ + if (events == BH_POLLIRQ) { + espi_hw_handle_irq(); + return; + } else { + switch (events) { + case BH_WAKEUP: + espi_async_handler(); + break; + default: + BUG(); + } + } +} + +#ifdef SYS_REALTIME +void __espi_poll_init(void) +{ + irq_register_poller(espi_bh); +} +#else +void __espi_irq_init(void) +{ + espi_hw_irq_init(); +} +#endif + +void espi_write_cmd(uint8_t opcode, uint8_t hlen, uint8_t *hbuf, + uint8_t dlen, uint8_t *dbuf) +{ + espi_cmd = opcode; + espi_hw_write_cmd(opcode, hlen, hbuf, dlen, dbuf); +} + void espi_init(void) { + espi_bh = bh_register_handler(espi_bh_handler); + espi_irq_init(); + espi_poll_init(); + + espi_state = ESPI_STATE_INIT; + espi_event = 0; + espi_op = ESPI_OP_NONE; + espi_cmd = ESPI_CMD_NONE; + espi_hw_ctrl_init(); + espi_raise_event(ESPI_EVENT_SETUP); }