// Copyright 2020-2021 Beken // // 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. #pragma once #include "qspi_hw.h" #include #include #include "sys_hal.h" #ifdef __cplusplus extern "C" { #endif #define QSPI_LL_REG_BASE(_qspi_unit_id) (SOC_QSPI0_REG_BASE + (0x20000 * _qspi_unit_id)) #define QSPI_DATA_LL_REG_BASE(_qspi_unit_id) (SOC_QSPI0_DATA_BASE + (0x4000000 * _qspi_unit_id)) #define QSPI0_LL_CLK_PIN GPIO_22 #define QSPI0_LL_CSN_PIN GPIO_23 #define QSPI0_LL_IO0_PIN GPIO_24 #define QSPI0_LL_IO1_PIN GPIO_25 #define QSPI0_LL_IO2_PIN GPIO_26 #define QSPI0_LL_IO3_PIN GPIO_27 #define QSPI1_LL_CLK_PIN GPIO_2 #define QSPI1_LL_CSN_PIN GPIO_3 #define QSPI1_LL_IO0_PIN GPIO_4 #define QSPI1_LL_IO1_PIN GPIO_5 #define QSPI1_LL_IO2_PIN GPIO_6 #define QSPI1_LL_IO3_PIN GPIO_7 #define READ_ID_CMD 0x9F #define ENTER_QUAD_MODE_CMD 0x35 #define EXIT_QUAD_MODE_CMD 0xF5 #define QUAD_WRITE_CMD 0x38 #define WRITE_CMD 0x02 #define FAST_READ_QUAD 0xEB #define FAST_READ 0x0B #define READ_CMD 0x03 #define FLASH_READ_ID_CMD 0x9F #define FLASH_WR_S0_S7_CMD 0x1 #define FLASH_WR_S8_S15_CMD 0x31 #define FLASH_RD_S0_S7_CMD 0x5 #define FLASH_RD_S8_S15_CMD 0x35 #define FLASH_WR_EN_CMD 0x6 #define FLASH_WR_CMD 0x2 #define FLASH_RD_CMD 0x3 #define FLASH_QUAD_WR_CMD 0x32 #define FLASH_QUAD_RD_CMD 0xeb #define FLASH_ERASE_SECTOR_CMD 0x20 //TODO init more static inline void qspi_ll_init(qspi_hw_t *hw) { } static inline void qspi_ll_set_cmd_a_l(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_a_l.v = cmd_value; } static inline void qspi_ll_set_cmd_a_h(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_a_h.v = cmd_value; } static inline void qspi_ll_set_cmd_a_cfg1(qspi_hw_t *hw, uint32_t cmd_line) { hw->cmd_a_cfg1.v = cmd_line; } static inline void qspi_ll_set_cmd_a_cfg2(qspi_hw_t *hw, uint32_t cmd_config) { hw->cmd_a_cfg2.v = cmd_config; } static inline void qspi_ll_set_cmd_a_data_line(qspi_hw_t *hw, qspi_wire_mode_t data_line) { hw->cmd_a_cfg2.data_line = data_line; } static inline void qspi_ll_set_cmd_a_dummy_clock(qspi_hw_t *hw, uint32_t dummy_clock) { hw->cmd_a_cfg2.dummy_clock = dummy_clock & QSPI_F_DUMMY_CLK_M; } static inline void qspi_ll_set_cmd_b_l(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_b_l.v = cmd_value; } static inline void qspi_ll_set_cmd_b_h(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_b_h.v = cmd_value; } static inline void qspi_ll_set_cmd_b_cfg1(qspi_hw_t *hw, uint32_t cmd_line) { hw->cmd_b_cfg1.v = cmd_line; } static inline void qspi_ll_set_cmd_b_data_line(qspi_hw_t *hw, qspi_wire_mode_t data_line) { hw->cmd_b_cfg2.data_line = data_line; } static inline void qspi_ll_set_cmd_b_dummy_clock(qspi_hw_t *hw, uint32_t dummy_clock) { hw->cmd_b_cfg2.dummy_clock = dummy_clock & QSPI_F_DUMMY_CLK_M; } static inline void qspi_ll_set_cmd_c_l(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_c_l.v = cmd_value; } static inline uint32_t qspi_ll_get_cmd_c_l(qspi_hw_t *hw) { return hw->cmd_c_l.v; } static inline void qspi_ll_set_cmd_c_h(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_c_h.v = cmd_value; } static inline uint32_t qspi_ll_get_cmd_c_h(qspi_hw_t *hw) { return hw->cmd_c_h.v; } static inline void qspi_ll_set_cmd_c_cfg1(qspi_hw_t *hw, uint32_t cmd_line) { hw->cmd_c_cfg1.v = cmd_line; } static inline void qspi_ll_set_cmd_c_cfg2(qspi_hw_t *hw, uint32_t config_value) { hw->cmd_c_cfg2.v = config_value; } static inline void qspi_ll_cmd_c_start(qspi_hw_t *hw) { hw->cmd_c_cfg2.cmd_start = 1; } static inline void qspi_ll_set_cmd_c_data_line(qspi_hw_t *hw, qspi_wire_mode_t data_line) { hw->cmd_c_cfg2.data_line = data_line; } static inline void qspi_ll_set_cmd_c_dummy_clock(qspi_hw_t *hw, uint32_t dummy_clock) { hw->cmd_c_cfg2.dummy_clock = dummy_clock & QSPI_F_DUMMY_CLK_M; } static inline void qspi_ll_set_cmd_d_l(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_d_l.v = cmd_value; } static inline uint32_t qspi_ll_get_cmd_d_l(qspi_hw_t *hw) { return hw->cmd_d_l.v; } static inline void qspi_ll_set_cmd_d_h(qspi_hw_t *hw, uint32_t cmd_value) { hw->cmd_d_h.v = cmd_value; } static inline uint32_t qspi_ll_get_cmd_d_h(qspi_hw_t *hw) { return hw->cmd_d_h.v; } static inline void qspi_ll_set_cmd_d_cfg1(qspi_hw_t *hw, uint32_t cmd_line) { hw->cmd_d_cfg1.v = cmd_line; } static inline void qspi_ll_set_cmd_d_cfg2(qspi_hw_t *hw, uint32_t config_value) { hw->cmd_d_cfg2.v = config_value; } static inline void qspi_ll_cmd_d_start(qspi_hw_t *hw) { hw->cmd_d_cfg2.cmd_start = 1; } static inline void qspi_ll_set_cmd_d_data_line(qspi_hw_t *hw, qspi_wire_mode_t data_line) { hw->cmd_d_cfg2.data_line = data_line; } static inline void qspi_ll_set_cmd_d_data_length(qspi_hw_t *hw, qspi_wire_mode_t data_len) { hw->cmd_d_cfg2.data_len = data_len; } static inline void qspi_ll_set_cmd_d_dummy_clock(qspi_hw_t *hw, uint32_t dummy_clock) { hw->cmd_d_cfg2.dummy_clock = dummy_clock & QSPI_F_DUMMY_CLK_M; } static inline void qspi_ll_set_cmd_d_dummy_mode(qspi_hw_t *hw, uint32_t dummy_mode) { hw->cmd_d_cfg2.dummy_mode = dummy_mode & 0x7; } static inline void qspi_ll_enable(qspi_hw_t *hw) { hw->config.qspi_en = 1; } static inline void qspi_ll_disable(qspi_hw_t *hw) { hw->config.qspi_en = 0; } static inline void qspi_ll_enable_io2_io3_mode(qspi_hw_t *hw) { hw->config.io2_io3_mode = 1; } static inline void qspi_ll_disable_io2_io3_mode(qspi_hw_t *hw) { hw->config.io2_io3_mode = 0; } static inline void qspi_ll_force_spi_cs_low_enable(qspi_hw_t *hw) { hw->config.force_spi_cs_low = 1; } static inline void qspi_ll_force_spi_cs_low_disable(qspi_hw_t *hw) { hw->config.force_spi_cs_low = 0; } static inline void qspi_ll_disable_cmd_sck_enable(qspi_hw_t *hw) { hw->config.disable_cmd_sck = 1; } static inline void qspi_ll_disable_cmd_sck_disable(qspi_hw_t *hw) { hw->config.disable_cmd_sck = 0; } static inline void qspi_ll_set_clk_div(qspi_hw_t *hw, uint32_t clk_div) { hw->config.v &= (~(QSPI_F_CLK_DIV_M << QSPI_F_CLK_DIV_S)); hw->config.v |= ((clk_div & QSPI_F_CLK_DIV_M) << QSPI_F_CLK_DIV_S); } static inline void qspi_ll_select_io_cpu_mem(qspi_hw_t *hw, uint32_t mem_sel) { hw->config.io_cpu_mem_sel = mem_sel; } static inline bool qspi_ll_is_cmd_start_done(qspi_hw_t *hw) { return !!(hw->status.cmd_start_done); } static inline void qspi_ll_wait_cmd_done(qspi_hw_t *hw) { for(int i = 0; i <= 10000; i++) { if(0 != qspi_ll_is_cmd_start_done(hw)) { break; } if(i == 10000) { os_printf("ERROR: qspi_ll_wait_cmd_done timeout \n"); } extern void delay_us(UINT32 us); delay_us(1); } hw->status_clr.clr_cmd_start_done = 1; hw->status_clr.clr_cmd_start_done = 0; } /* Start for qspi lcd with no ram and refresh by line */ static inline void qspi_ll_enable_soft_reset(qspi_hw_t *hw) { hw->glb_ctrl.soft_reset = 1; } static inline void qspi_ll_disable_soft_reset(qspi_hw_t *hw) { hw->glb_ctrl.soft_reset = 0; } static inline void qspi_ll_set_cmd_last_addr(qspi_hw_t *hw, uint32_t addr_value) { hw->reg30.cmd_last_addr = addr_value; } static inline void qspi_ll_set_lcd_head_cmd0(qspi_hw_t *hw, uint32_t cmd_value) { hw->lcd_head_cmd0 = cmd_value; } static inline void qspi_ll_set_lcd_head_cmd1(qspi_hw_t *hw, uint32_t cmd_value) { hw->lcd_head_cmd1 = cmd_value; } static inline void qspi_ll_set_lcd_head_cmd2(qspi_hw_t *hw, uint32_t cmd_value) { hw->lcd_head_cmd2 = cmd_value; } static inline void qspi_ll_set_lcd_head_cmd3(qspi_hw_t *hw, uint32_t cmd_value) { hw->lcd_head_cmd3 = cmd_value; } static inline void qspi_ll_set_lcd_head_hcnt(qspi_hw_t *hw, uint32_t hcnt_value) { hw->reg35.lcd_head_hcnt = hcnt_value; } static inline void qspi_ll_set_lcd_head_vcnt(qspi_hw_t *hw, uint32_t vcnt_value) { hw->reg35.lcd_head_vcnt = vcnt_value; } static inline void qspi_ll_clear_lcd_head(qspi_hw_t *hw, uint32_t value) { hw->reg36.lcd_head_clr = value; } static inline void qspi_ll_lcd_head_enable(qspi_hw_t *hw) { hw->reg36.lcd_head_sel = 1; } static inline void qspi_ll_lcd_head_disable(qspi_hw_t *hw) { hw->reg36.lcd_head_sel = 0; } static inline void qspi_ll_set_lcd_head_length(qspi_hw_t *hw, uint32_t length) { hw->reg36.lcd_head_len = length; } static inline void qspi_ll_set_lcd_head_interval(qspi_hw_t *hw, uint32_t intv_cnt) { hw->reg36.lcd_head_dly = intv_cnt; } /* End for qspi lcd with no ram and refresh by line */ static inline void qspi_ll_direct_write(qspi_id_t id, uint32_t base_addr, const void *data, uint32_t size) { for (int i = 0; i < size; i++) { *((uint8_t *)(QSPI_DATA_LL_REG_BASE(id) + base_addr + i)) = *((uint8_t *)data + i); } } static inline void qspi_ll_direct_read(qspi_id_t id, uint32_t base_addr, void *data, uint32_t size) { for (int i = 0; i < size; i++) { *((uint8_t *)data + i) = *((uint8_t *)(QSPI_DATA_LL_REG_BASE(id) + base_addr + i)); } } static inline void qspi_ll_io_write(qspi_hw_t *hw, const void *data, uint32_t data_len) { uint32_t fifo_num = 0; if(0 == (data_len % 4)) { fifo_num = data_len / 4; } else { fifo_num = (data_len / 4) + 1; } for(uint32_t i = 0; i < fifo_num; i++) { *((uint32_t *)(hw->fifo_data) + i) = *((uint32_t *)data + i); } } static inline void qspi_ll_io_read(qspi_hw_t *hw, void *data, uint32_t data_len) { uint32_t size = 0; if(0 == (data_len % 4)) { size = data_len / 4; } else { size = (data_len / 4) + 1; } for(uint32_t i = 0; i < size; i++) { *((uint32_t *)data + i) = *((uint32_t *)(hw->fifo_data) + i); } } static inline void qspi_ll_init_command(qspi_hw_t *hw, const qspi_cmd_t *cmd) { uint8_t addr_h; uint8_t addr_m; uint8_t addr_l; if(QSPI_FLASH == cmd->device) { if(INDIRECT_MODE == cmd->work_mode) { if(QSPI_WRITE == cmd->op) { hw->cmd_c_l.v = 0; hw->cmd_c_h.v &= (~(QSPI_F_CMD1_M << QSPI_F_CMD1_S)); hw->cmd_c_h.v |= (cmd->cmd & (QSPI_F_CMD1_M << QSPI_F_CMD1_S)); if(FLASH_WR_S0_S7_CMD == ((cmd->cmd) & QSPI_F_CMD1_M) || (FLASH_WR_S8_S15_CMD == ((cmd->cmd) & QSPI_F_CMD1_M))) { hw->cmd_c_h.v &= (~(QSPI_F_CMD2_M << QSPI_F_CMD2_S)); hw->cmd_c_h.v |= (cmd->cmd & (QSPI_F_CMD2_M << QSPI_F_CMD2_S)); if (cmd->cmd & (QSPI_F_CMD3_M << QSPI_F_CMD3_S)) { hw->cmd_c_h.v &= (~(QSPI_F_CMD3_M << QSPI_F_CMD3_S)); hw->cmd_c_h.v |= (cmd->cmd & (QSPI_F_CMD3_M << QSPI_F_CMD3_S)); hw->cmd_c_cfg1.v = 0xc0; } else { hw->cmd_c_cfg1.v = 0x30; } } else if (FLASH_WR_EN_CMD == ((cmd->cmd) & QSPI_F_CMD1_M)) { hw->cmd_c_cfg1.v = 0xc; } else { addr_h = (cmd->addr & 0xff0000) >> 16; addr_m = (cmd->addr & 0x00ff00) >> 8; addr_l = cmd->addr & 0x0000ff; hw->cmd_c_h.v &= (~(QSPI_F_CMD2_M << QSPI_F_CMD2_S)); hw->cmd_c_h.v |= ((addr_h & QSPI_F_CMD2_M) << QSPI_F_CMD2_S); hw->cmd_c_h.v &= (~(QSPI_F_CMD3_M << QSPI_F_CMD3_S)); hw->cmd_c_h.v |= ((addr_m & QSPI_F_CMD3_M) << QSPI_F_CMD3_S); hw->cmd_c_h.v &= (~(QSPI_F_CMD4_M << QSPI_F_CMD4_S)); hw->cmd_c_h.v |= ((addr_l & QSPI_F_CMD4_M) << QSPI_F_CMD4_S); hw->cmd_c_cfg1.v = 0x300; } hw->cmd_c_cfg2.data_len = cmd->data_len; hw->cmd_c_cfg2.data_line = cmd->wire_mode; hw->cmd_c_cfg2.dummy_clock = cmd->dummy_cycle; if (cmd->dummy_cycle) { hw->cmd_c_cfg2.dummy_mode = 4; } else { hw->cmd_c_cfg2.dummy_mode = 0; } hw->cmd_c_cfg2.cmd_start = 1; qspi_ll_wait_cmd_done(hw); return; } else { hw->cmd_d_l.v = 0; hw->cmd_d_h.v &= (~(QSPI_F_CMD1_M << QSPI_F_CMD1_S)); hw->cmd_d_h.v |= (cmd->cmd & (QSPI_F_CMD1_M << QSPI_F_CMD1_S)); if((FLASH_RD_S0_S7_CMD == cmd->cmd) || (FLASH_RD_S8_S15_CMD == cmd->cmd) || (FLASH_READ_ID_CMD == cmd->cmd)) { hw->cmd_d_cfg1.v = 0xc; } else { addr_h = (cmd->addr & 0xff0000) >> 16; addr_m = (cmd->addr & 0x00ff00) >> 8; addr_l = cmd->addr & 0x0000ff; hw->cmd_d_h.v &= (~(QSPI_F_CMD2_M << QSPI_F_CMD2_S)); hw->cmd_d_h.v |= ((addr_h & QSPI_F_CMD2_M) << QSPI_F_CMD2_S); hw->cmd_d_h.v &= (~(QSPI_F_CMD3_M << QSPI_F_CMD3_S)); hw->cmd_d_h.v |= ((addr_m & QSPI_F_CMD3_M) << QSPI_F_CMD3_S); hw->cmd_d_h.v &= (~(QSPI_F_CMD4_M << QSPI_F_CMD4_S)); hw->cmd_d_h.v |= ((addr_l & QSPI_F_CMD4_M) << QSPI_F_CMD4_S); if(QSPI_4WIRE == cmd->wire_mode) { hw->cmd_d_cfg1.v = 0xea8; } else { hw->cmd_d_cfg1.v = 0x300; } } hw->cmd_d_cfg2.data_len = cmd->data_len; hw->cmd_d_cfg2.data_line = cmd->wire_mode; hw->cmd_d_cfg2.dummy_clock = cmd->dummy_cycle; if (cmd->dummy_cycle) { hw->cmd_d_cfg2.dummy_mode = 5; } else { hw->cmd_d_cfg2.dummy_mode = 0; } hw->cmd_d_cfg2.cmd_start = 1; qspi_ll_wait_cmd_done(hw); return; } } }else { if(MEMORY_MAPPED_MODE == cmd->work_mode) { if(QSPI_WRITE == cmd->op) { hw->cmd_a_l.v = 0; hw->cmd_a_h.cmd1 = cmd->cmd; if(QUAD_WRITE_CMD == cmd->cmd) { hw->cmd_a_cfg1.v = 0x3aa; } else if (WRITE_CMD == cmd->cmd) { hw->cmd_a_cfg1.v = 0x300; } hw->cmd_a_cfg2.data_line = cmd->wire_mode; hw->cmd_a_cfg2.dummy_clock = cmd->dummy_cycle; if (cmd->dummy_cycle) { hw->cmd_a_cfg2.dummy_mode = 4; } else { hw->cmd_a_cfg2.dummy_mode = 0; } //hw->cmd_a_cfg2.cmd_mode = cmd->cmd_mode; } else { hw->cmd_b_l.v = 0; hw->cmd_b_h.cmd1 = cmd->cmd; if(FAST_READ_QUAD == cmd->cmd) { if (QSPI_1WIRE == cmd->wire_mode) { hw->cmd_b_cfg1.v = 0x3a8; } else if (QSPI_4WIRE == cmd->wire_mode) { hw->cmd_b_cfg1.v = 0x3aa; } } else if (READ_CMD == cmd->cmd) { hw->cmd_b_cfg1.v = 0x300; } hw->cmd_b_cfg2.data_line = cmd->wire_mode; hw->cmd_b_cfg2.dummy_clock = cmd->dummy_cycle; if (cmd->dummy_cycle) { hw->cmd_b_cfg2.dummy_mode = 4; } else { hw->cmd_b_cfg2.dummy_mode = 0; } //hw->cmd_b_cfg2.cmd_mode = cmd->cmd_mode; } return; } else { if(QSPI_WRITE == cmd->op) { hw->cmd_c_l.v = 0; hw->cmd_c_h.v &= (~(QSPI_F_CMD1_M << QSPI_F_CMD1_S)); hw->cmd_c_h.v |= (cmd->cmd & (QSPI_F_CMD1_M << QSPI_F_CMD1_S)); if(ENTER_QUAD_MODE_CMD == cmd->cmd) { hw->cmd_c_cfg1.v = 0xc; } else if (EXIT_QUAD_MODE_CMD == cmd->cmd) { hw->cmd_c_cfg1.v = 0xe; } hw->cmd_c_cfg2.data_line = cmd->wire_mode; hw->cmd_c_cfg2.dummy_clock = cmd->dummy_cycle; if (cmd->dummy_cycle) { hw->cmd_c_cfg2.dummy_mode = 4; } else { hw->cmd_c_cfg2.dummy_mode = 0; } hw->cmd_c_cfg2.cmd_start = 1; qspi_ll_wait_cmd_done(hw); return; } else { hw->cmd_d_l.v = 0; hw->cmd_d_h.cmd1 = cmd->cmd; hw->cmd_d_cfg1.v = 0xc; hw->cmd_d_cfg2.data_line = cmd->wire_mode; hw->cmd_d_cfg2.dummy_clock = cmd->dummy_cycle; if (cmd->dummy_cycle) { hw->cmd_d_cfg2.dummy_mode = 4; } else { hw->cmd_d_cfg2.dummy_mode = 0; } hw->cmd_d_cfg2.cmd_start = 1; qspi_ll_wait_cmd_done(hw); return; } } } } static inline void qspi_ll_init_common(qspi_hw_t *hw) { qspi_ll_enable(hw); qspi_ll_enable_io2_io3_mode(hw); } static inline void qspi_ll_deinit_common(qspi_hw_t *hw) { qspi_ll_disable(hw); qspi_ll_disable_io2_io3_mode(hw); } static inline uint32_t qspi_ll_get_interrupt_status_before_mask(qspi_hw_t *hw) { return hw->status.v; } static inline void qspi_ll_clear_interrupt_status(qspi_hw_t *hw, uint32_t status) { hw->status_clr.v = status; hw->status_clr.v = 0; } static inline uint32_t qspi_ll_get_interrupt_status_after_mask(qspi_hw_t *hw) { return 0; } static inline bool qspi_ll_is_sw_op_int_triggered(qspi_hw_t *hw, uint32_t status) { return 0; } static inline void qspi_ll_clear_sw_op_int(qspi_hw_t *hw) { } static inline void qspi_ll_enable_sw_op_int_mask(qspi_hw_t *hw) { } static inline void qspi_ll_disable_sw_op_int_mask(qspi_hw_t *hw) { } static inline void qspi_ll_stop_sw_op(qspi_hw_t *hw) { } static inline void qspi_ll_disable_ge0_tx(qspi_hw_t *hw) { } static inline void qspi_ll_disable_ge1_rx(qspi_hw_t *hw) { } #ifdef __cplusplus } #endif