aboutsummaryrefslogtreecommitdiff
path: root/libiot/hal
diff options
context:
space:
mode:
authorbhgv <bhgv.empire@gmail.com>2020-05-10 02:59:23 +0300
committerbhgv <bhgv.empire@gmail.com>2020-05-10 02:59:23 +0300
commit31b4edc67b75658ce5e2d41f2fc87331f4b26d49 (patch)
treea7b6ea659fe62e0a7239f29170024f524595fb4d /libiot/hal
parentc76314f0f38f4ed028610a6db4452879a556b35f (diff)
a try to add support of FreeRTOS riscV-64 (k210 cpu). first step
Diffstat (limited to 'libiot/hal')
-rw-r--r--libiot/hal/mkfile3
-rw-r--r--libiot/hal/w25qxx.c288
-rw-r--r--libiot/hal/w25qxx.h88
3 files changed, 379 insertions, 0 deletions
diff --git a/libiot/hal/mkfile b/libiot/hal/mkfile
new file mode 100644
index 0000000..73b16cb
--- /dev/null
+++ b/libiot/hal/mkfile
@@ -0,0 +1,3 @@
+OFILES=\
+ $OFILES\
+ hal/w25qxx.$O\
diff --git a/libiot/hal/w25qxx.c b/libiot/hal/w25qxx.c
new file mode 100644
index 0000000..a169617
--- /dev/null
+++ b/libiot/hal/w25qxx.c
@@ -0,0 +1,288 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <devices.h>
+#include "w25qxx.h"
+
+uintptr_t spi_adapter;
+uintptr_t spi_stand;
+
+static enum w25qxx_status_t w25qxx_receive_data(uint8_t* cmd_buff, uint8_t cmd_len, uint8_t* rx_buff, uint32_t rx_len)
+{
+ spi_dev_transfer_sequential(spi_stand, (uint8_t *)cmd_buff, cmd_len, (uint8_t *)rx_buff, rx_len);
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_receive_data_enhanced(uint32_t* cmd_buff, uint8_t cmd_len, uint8_t* rx_buff, uint32_t rx_len)
+{
+ memcpy(rx_buff, cmd_buff, cmd_len);
+ io_read(spi_adapter, (uint8_t *)rx_buff, rx_len);
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_send_data(uintptr_t file, uint8_t* cmd_buff, uint8_t cmd_len, uint8_t* tx_buff, uint32_t tx_len)
+{
+ configASSERT(cmd_len);
+ uint8_t* tmp_buf = malloc(cmd_len + tx_len);
+ memcpy(tmp_buf, cmd_buff, cmd_len);
+ if (tx_len)
+ memcpy(tmp_buf + cmd_len, tx_buff, tx_len);
+ io_write(file, (uint8_t *)tmp_buf, cmd_len + tx_len);
+ free(tmp_buf);
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_write_enable(void)
+{
+ uint8_t cmd[1] = {WRITE_ENABLE};
+
+ w25qxx_send_data(spi_stand, cmd, 1, 0, 0);
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t* reg_data)
+{
+ uint8_t cmd[1] = {READ_REG1};
+ uint8_t data[1];
+
+ w25qxx_receive_data(cmd, 1, data, 1);
+ *reg_data = data[0];
+ return W25QXX_OK;
+}
+static enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t* reg_data)
+{
+ uint8_t cmd[1] = {READ_REG2};
+ uint8_t data[1];
+
+ w25qxx_receive_data(cmd, 1, data, 1);
+ *reg_data = data[0];
+ return W25QXX_OK;
+}
+static enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data)
+{
+ uint8_t cmd[3] = {WRITE_REG1, reg1_data, reg2_data};
+
+ w25qxx_write_enable();
+ w25qxx_send_data(spi_stand, cmd, 3, 0, 0);
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_enable_quad_mode(void)
+{
+ uint8_t reg_data;
+
+ w25qxx_read_status_reg2(&reg_data);
+ if (!(reg_data & REG2_QUAL_MASK))
+ {
+ reg_data |= REG2_QUAL_MASK;
+ w25qxx_write_status_reg(0x00, reg_data);
+ }
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_is_busy(void)
+{
+ uint8_t status;
+
+ w25qxx_read_status_reg1(&status);
+ if (status & REG1_BUSY_MASK)
+ return W25QXX_BUSY;
+ return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr)
+{
+ uint8_t cmd[4] = {SECTOR_ERASE};
+
+ cmd[1] = (uint8_t)(addr >> 16);
+ cmd[2] = (uint8_t)(addr >> 8);
+ cmd[3] = (uint8_t)(addr);
+ w25qxx_write_enable();
+ w25qxx_send_data(spi_stand, cmd, 4, 0, 0);
+ return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id)
+{
+ uint8_t cmd[4] = {READ_ID, 0x00, 0x00, 0x00};
+ uint8_t data[2] = {0};
+
+ w25qxx_receive_data(cmd, 4, data, 2);
+ *manuf_id = data[0];
+ *device_id = data[1];
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_read_data_less_64kb(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+ uint32_t cmd[2];
+
+ switch (WORK_TRANS_MODE)
+ {
+ case SPI_FF_DUAL:
+ *(((uint8_t*)cmd) + 0) = FAST_READ_DUAL_OUTPUT;
+ *(((uint8_t*)cmd) + 1) = (uint8_t)(addr >> 0);
+ *(((uint8_t*)cmd) + 2) = (uint8_t)(addr >> 8);
+ *(((uint8_t*)cmd) + 3) = (uint8_t)(addr >> 16);
+ w25qxx_receive_data_enhanced(cmd, 4, data_buf, length);
+ break;
+ case SPI_FF_QUAD:
+ *(((uint8_t*)cmd) + 0) = FAST_READ_QUAL_OUTPUT;
+ *(((uint8_t*)cmd) + 1) = (uint8_t)(addr >> 0);
+ *(((uint8_t*)cmd) + 2) = (uint8_t)(addr >> 8);
+ *(((uint8_t*)cmd) + 3) = (uint8_t)(addr >> 16);
+ w25qxx_receive_data_enhanced(cmd, 4, data_buf, length);
+ break;
+ case SPI_FF_STANDARD:
+ default:
+ *(((uint8_t*)cmd) + 0) = READ_DATA;
+ *(((uint8_t*)cmd) + 1) = (uint8_t)(addr >> 16);
+ *(((uint8_t*)cmd) + 2) = (uint8_t)(addr >> 8);
+ *(((uint8_t*)cmd) + 3) = (uint8_t)(addr >> 0);
+ w25qxx_receive_data((uint8_t*)cmd, 4, data_buf, length);
+ break;
+ }
+ return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+ uint32_t len;
+
+ while (length)
+ {
+ len = length >= 0x010000 ? 0x010000 : length;
+ w25qxx_read_data_less_64kb(addr, data_buf, len);
+ addr += len;
+ data_buf += len;
+ length -= len;
+ }
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+ uint32_t cmd[2];
+ w25qxx_write_enable();
+ if (WORK_TRANS_MODE == SPI_FF_QUAD)
+ {
+ *(((uint8_t*)cmd) + 0) = QUAD_PAGE_PROGRAM;
+ *(((uint8_t*)cmd) + 1) = (uint8_t)(addr >> 0);
+ *(((uint8_t*)cmd) + 2) = (uint8_t)(addr >> 8);
+ *(((uint8_t*)cmd) + 3) = (uint8_t)(addr >> 16);
+ w25qxx_send_data(spi_adapter, (uint8_t*)cmd, 4, data_buf, length);
+ }
+ else
+ {
+ *(((uint8_t*)cmd) + 0) = PAGE_PROGRAM;
+ *(((uint8_t*)cmd) + 1) = (uint8_t)(addr >> 16);
+ *(((uint8_t*)cmd) + 2) = (uint8_t)(addr >> 8);
+ *(((uint8_t*)cmd) + 3) = (uint8_t)(addr >> 0);
+ w25qxx_send_data(spi_stand, (uint8_t*)cmd, 4, data_buf, length);
+ }
+ while (w25qxx_is_busy() == W25QXX_BUSY)
+ ;
+ return W25QXX_OK;
+}
+
+static enum w25qxx_status_t w25qxx_sector_program(uint32_t addr, uint8_t* data_buf)
+{
+ uint8_t index;
+
+ for (index = 0; index < w25qxx_FLASH_PAGE_NUM_PER_SECTOR; index++)
+ {
+ w25qxx_page_program(addr, data_buf, w25qxx_FLASH_PAGE_SIZE);
+ addr += w25qxx_FLASH_PAGE_SIZE;
+ data_buf += w25qxx_FLASH_PAGE_SIZE;
+ }
+ return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t* data_buf, uint32_t length)
+{
+ uint32_t sector_addr, sector_offset, sector_remain, write_len, index;
+ uint8_t swap_buf[w25qxx_FLASH_SECTOR_SIZE];
+ uint8_t *pread, *pwrite;
+
+ while (length)
+ {
+ sector_addr = addr & (~(w25qxx_FLASH_SECTOR_SIZE - 1));
+ sector_offset = addr & (w25qxx_FLASH_SECTOR_SIZE - 1);
+ sector_remain = w25qxx_FLASH_SECTOR_SIZE - sector_offset;
+ write_len = length < sector_remain ? length : sector_remain;
+ w25qxx_read_data(sector_addr, swap_buf, w25qxx_FLASH_SECTOR_SIZE);
+ pread = swap_buf + sector_offset;
+ pwrite = data_buf;
+ for (index = 0; index < write_len; index++)
+ {
+ if ((*pwrite) != ((*pwrite) & (*pread)))
+ {
+ w25qxx_sector_erase(sector_addr);
+ while (w25qxx_is_busy() == W25QXX_BUSY)
+ ;
+ break;
+ }
+ pwrite++;
+ pread++;
+ }
+ if (write_len == w25qxx_FLASH_SECTOR_SIZE)
+ w25qxx_sector_program(sector_addr, data_buf);
+ else
+ {
+ pread = swap_buf + sector_offset;
+ pwrite = data_buf;
+ for (index = 0; index < write_len; index++)
+ *pread++ = *pwrite++;
+ w25qxx_sector_program(sector_addr, swap_buf);
+ }
+ length -= write_len;
+ addr += write_len;
+ data_buf += write_len;
+ }
+ return W25QXX_OK;
+}
+
+enum w25qxx_status_t w25qxx_init(uintptr_t spi_in)
+{
+ uint8_t manuf_id, device_id;
+ spi_stand = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_STANDARD, CHIP_SELECT, FRAME_LENGTH);
+ spi_dev_set_clock_rate(spi_stand, 800000);
+ w25qxx_read_id(&manuf_id, &device_id);
+ if ((manuf_id != 0xEF && manuf_id != 0xC8) || (device_id != 0x17 && device_id != 0x16))
+ {
+ printf("manuf_id:0x%02x, device_id:0x%02x\n", manuf_id, device_id);
+ }
+ printf("manuf_id:0x%02x, device_id:0x%02x\n", manuf_id, device_id);
+ switch (WORK_TRANS_MODE)
+ {
+ case SPI_FF_DUAL:
+ spi_adapter = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_DUAL, CHIP_SELECT, FRAME_LENGTH);
+ spi_dev_config_non_standard(spi_adapter, INSTRUCTION_LENGTH, ADDRESS_LENGTH, WAIT_CYCLE, SPI_AITM_STANDARD);
+ break;
+ case SPI_FF_QUAD:
+ spi_adapter = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_QUAD, CHIP_SELECT, FRAME_LENGTH);
+ spi_dev_config_non_standard(spi_adapter, INSTRUCTION_LENGTH, ADDRESS_LENGTH, WAIT_CYCLE, SPI_AITM_STANDARD);
+ w25qxx_enable_quad_mode();
+ break;
+ case SPI_FF_STANDARD:
+ default:
+ spi_adapter = spi_stand;
+ break;
+ }
+ return W25QXX_OK;
+}
+
diff --git a/libiot/hal/w25qxx.h b/libiot/hal/w25qxx.h
new file mode 100644
index 0000000..5ae32ca
--- /dev/null
+++ b/libiot/hal/w25qxx.h
@@ -0,0 +1,88 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * 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 _W25QXX_H
+#define _W25QXX_H
+#include <stdint.h>
+
+/* clang-format off */
+#define WORK_TRANS_MODE SPI_FF_STANDARD
+/* #define WORK_TRANS_MODE SPI_FF_DUAL */
+/* #define WORK_TRANS_MODE SPI_FF_QUAD */
+
+#define CHIP_SELECT 1
+#define WAIT_CYCLE 8
+#define FRAME_LENGTH 8
+#define INSTRUCTION_LENGTH 8
+#define ADDRESS_LENGTH 24
+
+#define SPI_SLAVE_SELECT (0x01)
+
+#define w25qxx_FLASH_PAGE_SIZE 256
+#define w25qxx_FLASH_SECTOR_SIZE 4096
+#define w25qxx_FLASH_PAGE_NUM_PER_SECTOR 16
+#define w25qxx_FLASH_CHIP_SIZE (16777216 UL)
+
+#define WRITE_ENABLE 0x06
+#define WRITE_DISABLE 0x04
+#define READ_REG1 0x05
+#define READ_REG2 0x35
+#define READ_REG3 0x15
+#define WRITE_REG1 0x01
+#define WRITE_REG2 0x31
+#define WRITE_REG3 0x11
+#define READ_DATA 0x03
+#define FAST_READ 0x0B
+#define FAST_READ_DUAL_OUTPUT 0x3B
+#define FAST_READ_QUAL_OUTPUT 0x6B
+#define FAST_READ_DUAL_IO 0xBB
+#define FAST_READ_QUAL_IO 0xEB
+#define DUAL_READ_RESET 0xFFFF
+#define QUAL_READ_RESET 0xFF
+#define PAGE_PROGRAM 0x02
+#define QUAD_PAGE_PROGRAM 0x32
+#define SECTOR_ERASE 0x20
+#define BLOCK_32K_ERASE 0x52
+#define BLOCK_64K_ERASE 0xD8
+#define CHIP_ERASE 0x60
+#define READ_ID 0x90
+#define ENABLE_QPI 0x38
+#define EXIT_QPI 0xFF
+#define ENABLE_RESET 0x66
+#define RESET_DEVICE 0x99
+
+#define REG1_BUSY_MASK 0x01
+#define REG2_QUAL_MASK 0x02
+
+#define LETOBE(x) ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24))
+/* clang-format on */
+
+/**
+ * @brief w25qxx operating status enumerate
+ */
+enum w25qxx_status_t
+{
+ W25QXX_OK = 0,
+ W25QXX_BUSY,
+ W25QXX_ERROR,
+};
+
+enum w25qxx_status_t w25qxx_init(uintptr_t spi_in);
+enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t* data_buf, uint32_t length);
+enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t* data_buf, uint32_t length);
+
+enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr);
+
+#endif
+