345 lines
12 KiB
Diff
345 lines
12 KiB
Diff
From 734908adb47c32f41f450fa886d9500e9579d6ca Mon Sep 17 00:00:00 2001
|
|
From: huangyifeng <huangyifeng@eswincomputing.com>
|
|
Date: Mon, 12 Aug 2024 16:04:58 +0800
|
|
Subject: [PATCH 148/219] feat:KASAN warnning & bootspi region protection
|
|
|
|
Changelogs:
|
|
1.fix KASAN warnning of NOC and clock driver
|
|
2.bootspi support region write protection enable/disable
|
|
|
|
Signed-off-by: huangyifeng <huangyifeng@eswincomputing.com>
|
|
---
|
|
drivers/clk/eswin/clk-win2030.c | 24 ++--
|
|
drivers/interconnect/eswin/noc_sysfs.c | 2 +-
|
|
drivers/spi/spi-eswin-bootspi.c | 172 ++++++++++++++++++++++---
|
|
3 files changed, 172 insertions(+), 26 deletions(-)
|
|
|
|
diff --git a/drivers/clk/eswin/clk-win2030.c b/drivers/clk/eswin/clk-win2030.c
|
|
index 64bf0476b4bc..b7c382133ccc 100755
|
|
--- a/drivers/clk/eswin/clk-win2030.c
|
|
+++ b/drivers/clk/eswin/clk-win2030.c
|
|
@@ -277,14 +277,18 @@ static struct eswin_mux_clock win2030_mux_clks[] = {
|
|
|
|
};
|
|
|
|
-/*The hardware decides vaule 0, 1 and 2 both means 2 divsor, so we have to add these ugly tables*/
|
|
-static struct clk_div_table u_3_bit_special_div_table[8];
|
|
-static struct clk_div_table u_4_bit_special_div_table[16];
|
|
-static struct clk_div_table u_6_bit_special_div_table[64];
|
|
-static struct clk_div_table u_7_bit_special_div_table[128];
|
|
-static struct clk_div_table u_8_bit_special_div_table[256];
|
|
-static struct clk_div_table u_11_bit_special_div_table[2048];
|
|
-static struct clk_div_table u_16_bit_special_div_table[65536];
|
|
+/*
|
|
+ The hardware decides vaule 0, 1 and 2 both means 2 divsor, so we have to add these ugly tables.
|
|
+ When using these tables, the clock framework will use the last member being 0 as a marker to indicate the end of the table,
|
|
+ so an additional member is required.
|
|
+ */
|
|
+static struct clk_div_table u_3_bit_special_div_table[8 + 1];
|
|
+static struct clk_div_table u_4_bit_special_div_table[16 + 1];
|
|
+static struct clk_div_table u_6_bit_special_div_table[64 + 1];
|
|
+static struct clk_div_table u_7_bit_special_div_table[128 + 1];
|
|
+static struct clk_div_table u_8_bit_special_div_table[256 + 1];
|
|
+static struct clk_div_table u_11_bit_special_div_table[2048 + 1];
|
|
+static struct clk_div_table u_16_bit_special_div_table[65536 + 1];
|
|
|
|
static struct eswin_divider_clock win2030_div_clks[] = {
|
|
{ WIN2030_DIVDER_U_SYS_CFG_DIV_DYNM, "divder_u_sys_cfg_div_dynm", "fixed_rate_clk_spll0_fout3", 0,
|
|
@@ -1157,10 +1161,12 @@ static void special_div_table_init(struct clk_div_table *table, int table_size)
|
|
table[i].val = i;
|
|
table[i].div = 2;
|
|
}
|
|
- for (i = 3; i < table_size; i++) {
|
|
+ for (i = 3; i < table_size -1; i++) {
|
|
table[i].val = i;
|
|
table[i].div = i;
|
|
}
|
|
+ table[table_size -1].val = 0;
|
|
+ table[table_size -1].div = 0;
|
|
return;
|
|
}
|
|
|
|
diff --git a/drivers/interconnect/eswin/noc_sysfs.c b/drivers/interconnect/eswin/noc_sysfs.c
|
|
index e3b24a258818..fac895eedcb6 100644
|
|
--- a/drivers/interconnect/eswin/noc_sysfs.c
|
|
+++ b/drivers/interconnect/eswin/noc_sysfs.c
|
|
@@ -38,7 +38,7 @@
|
|
#define MAX_ENUM_SIZE 254
|
|
|
|
static int win2030_noc_user_flag_dump(char *buf,
|
|
- struct win2030_bitfield *bitfield, unsigned bf_value)
|
|
+ struct win2030_bitfield *bitfield, unsigned long bf_value)
|
|
{
|
|
int i;
|
|
int count = 1;
|
|
diff --git a/drivers/spi/spi-eswin-bootspi.c b/drivers/spi/spi-eswin-bootspi.c
|
|
index ee28701ab1b8..0cf0d34ea315 100644
|
|
--- a/drivers/spi/spi-eswin-bootspi.c
|
|
+++ b/drivers/spi/spi-eswin-bootspi.c
|
|
@@ -54,6 +54,14 @@
|
|
#define ES_SPI_CSR_15 0x3c /*CHIP_DESELECT_TIME*/
|
|
#define ES_SPI_CSR_16 0x40 /*POWER_DOWN_TIME*/
|
|
|
|
+/* Flash opcodes. */
|
|
+#define SPINOR_OP_RDSR3 0x15 /* Read status register 3 */
|
|
+#define SPINOR_OP_WRSR3 0x11 /* Write status register 3 */
|
|
+#define SPINOR_BLOCK_LOCK 0x36 /* Individual Block/Sector Lock */
|
|
+#define SPINOR_BLOCK_UNLOCK 0x39 /* Individual Block/Sector UnLock */
|
|
+#define SPINOR_GLOBAL_BLOCK_LOCK 0x7E /* global Block/Sector UnLock */
|
|
+#define SPINOR_GLOBAL_BLOCK_UNLOCK 0x98 /* global Block/Sector UnLock */
|
|
+
|
|
#define ES_SYSCSR_SPIMODECFG 0x340
|
|
|
|
#define ES_CONCSR_SPI_INTSEL 0x3c0
|
|
@@ -417,7 +425,7 @@ uint8_t eswin_bootspi_read_flash_status_register(struct es_spi_priv *priv,
|
|
return 0;
|
|
}
|
|
|
|
-uint8_t eswin_bootspi_write_flash_status_register(struct es_spi_priv *priv,
|
|
+static uint8_t eswin_bootspi_write_flash_status_register(struct es_spi_priv *priv,
|
|
uint8_t register_data, int flash_cmd)
|
|
{
|
|
u32 command;
|
|
@@ -441,7 +449,27 @@ uint8_t eswin_bootspi_write_flash_status_register(struct es_spi_priv *priv,
|
|
return 0;
|
|
}
|
|
|
|
-int eswin_bootspi_flash_write_protection_cfg(struct es_spi_priv *priv, int enable)
|
|
+static void eswin_bootspi_write_flash_global_block_lock_register(
|
|
+ struct es_spi_priv *priv, int flash_cmd)
|
|
+{
|
|
+ u32 command;
|
|
+
|
|
+ //Flash global block lock register not need data
|
|
+ eswin_bootspi_read_write_cfg(priv, 1, 0);
|
|
+
|
|
+ command = eswin_bootspi_read(priv, ES_SPI_CSR_06);
|
|
+ command &= ~((0xFF << 6) | (0x1 << 5) | (0xF << 1) | 0x1);
|
|
+ command |= ((flash_cmd << SPI_COMMAND_CODE_FIELD_POSITION) |
|
|
+ (SPI_COMMAND_MOVE_VALUE << SPI_COMMAND_MOVE_FIELD_POSITION) |
|
|
+ (SPIC_CMD_TYPE_CHIP_ERASE << SPI_COMMAND_TYPE_FIELD_POSITION) | SPI_COMMAND_VALID);
|
|
+ eswin_bootspi_write(priv, ES_SPI_CSR_06, command);
|
|
+
|
|
+ //Wait command finish
|
|
+ eswin_bootspi_wait_over(priv);
|
|
+ //printf("[%s %d]: command 0x%x\n",__func__,__LINE__, command);
|
|
+}
|
|
+
|
|
+static int eswin_bootspi_flash_global_wp_cfg(struct es_spi_priv *priv, int enable)
|
|
{
|
|
uint8_t register_data, request_register_data;
|
|
|
|
@@ -449,20 +477,33 @@ int eswin_bootspi_flash_write_protection_cfg(struct es_spi_priv *priv, int enabl
|
|
|
|
//Update status register1
|
|
eswin_bootspi_read_flash_status_register(priv, ®ister_data, SPINOR_OP_RDSR);
|
|
- /*
|
|
- SRP SEC TB BP2 BP1 BP0 WEL BUSY
|
|
- */
|
|
- if (enable) {
|
|
- request_register_data = register_data | ((1 << 2) | (1 << 3) | (1 << 4) | (1 << 7));
|
|
- } else {
|
|
- request_register_data = register_data & (~((1 << 2) | (1 << 3) | (1 << 4) | (1 << 7)));
|
|
+ request_register_data = register_data;
|
|
+ /*
|
|
+ SRP SEC TB BP2 BP1 BP0 WEL BUSY
|
|
+ */
|
|
+ request_register_data |= (1 << 5); //TB 1, bottom
|
|
+ request_register_data &= ~(1 << 6); // SEC 0, 64K
|
|
+ if (request_register_data != register_data) {
|
|
+ eswin_bootspi_write_flash_status_register(priv, request_register_data, SPINOR_OP_WRSR);
|
|
}
|
|
|
|
+ //Update status register3
|
|
+ eswin_bootspi_read_flash_status_register(priv, ®ister_data, SPINOR_OP_RDSR3);
|
|
+ request_register_data = register_data;
|
|
+ /*
|
|
+ R DRV1 DRV0 R R WPS R R
|
|
+ */
|
|
+ request_register_data |= (1 << 2); //WPS 1, individual block
|
|
if (request_register_data != register_data) {
|
|
- eswin_bootspi_write_flash_status_register(priv, request_register_data, SPINOR_OP_WRSR);
|
|
+ eswin_bootspi_write_flash_status_register(priv, request_register_data, SPINOR_OP_WRSR3);
|
|
}
|
|
|
|
- //eswin_bootspi_read_flash_status_register(priv, ®ister_data, SPINOR_OP_RDSR);
|
|
+ //Update global lock/unlock register
|
|
+ if (enable) {
|
|
+ eswin_bootspi_write_flash_global_block_lock_register(priv, SPINOR_GLOBAL_BLOCK_LOCK);
|
|
+ } else {
|
|
+ eswin_bootspi_write_flash_global_block_lock_register(priv, SPINOR_GLOBAL_BLOCK_UNLOCK);
|
|
+ }
|
|
|
|
external_cs_manage(priv, true);
|
|
return 0;
|
|
@@ -472,18 +513,18 @@ int eswin_bootspi_flash_write_protection_cfg(struct es_spi_priv *priv, int enabl
|
|
0: disable write_protection
|
|
1: enable write_protection
|
|
*/
|
|
-void eswin_bootspi_wp_cfg(struct es_spi_priv *priv, int enable)
|
|
+static void eswin_bootspi_wp_cfg(struct es_spi_priv *priv, int enable)
|
|
{
|
|
struct device *dev = priv->dev;
|
|
|
|
dev_info(dev, "Boot spi flash write protection %s\n", enable ? "enabled" : "disabled");
|
|
pm_runtime_get_sync(dev);
|
|
if (enable) {
|
|
- eswin_bootspi_flash_write_protection_cfg(priv, enable);
|
|
+ eswin_bootspi_flash_global_wp_cfg(priv, enable);
|
|
gpiod_set_value(priv->wp_gpio, enable); //gpio output low, enable protection
|
|
} else {
|
|
gpiod_set_value(priv->wp_gpio, enable); //gpio output high, disable protection
|
|
- eswin_bootspi_flash_write_protection_cfg(priv, enable);
|
|
+ eswin_bootspi_flash_global_wp_cfg(priv, enable);
|
|
}
|
|
pm_runtime_put_sync(dev);
|
|
}
|
|
@@ -514,6 +555,96 @@ static ssize_t wp_enable_store(struct device *dev,
|
|
|
|
static DEVICE_ATTR_RW(wp_enable);
|
|
|
|
+#define ALIGNMENT_SIZE 0x10000 // 64KB alignment
|
|
+static void eswin_bootspi_write_flash_individual_block_lock_register(
|
|
+ struct es_spi_priv *priv, u32 addr, int flash_cmd)
|
|
+{
|
|
+ u32 command;
|
|
+
|
|
+ eswin_bootspi_read_write_cfg(priv, 3, addr);
|
|
+
|
|
+ command = eswin_bootspi_read(priv, ES_SPI_CSR_06);
|
|
+ command &= ~((0xFF << 6) | (0x1 << 5) | (0xF << 1) | 0x1);
|
|
+ command |= ((flash_cmd << SPI_COMMAND_CODE_FIELD_POSITION) |
|
|
+ (SPI_COMMAND_MOVE_VALUE << SPI_COMMAND_MOVE_FIELD_POSITION) |
|
|
+ (SPIC_CMD_TYPE_BLOCK_ERASE_TYPE2 << SPI_COMMAND_TYPE_FIELD_POSITION) | SPI_COMMAND_VALID);
|
|
+
|
|
+ eswin_bootspi_write(priv, ES_SPI_CSR_06, command);
|
|
+
|
|
+ //Wait command finish
|
|
+ eswin_bootspi_wait_over(priv);
|
|
+
|
|
+ //printk("[%s %d]: command 0x%x, addr 0x%x, flash_cmd 0x%x\n",__func__,__LINE__, command, addr, flash_cmd);
|
|
+}
|
|
+
|
|
+static int eswin_bootspi_region_wp_cfg(struct es_spi_priv *priv, u32 addr, u32 size, int enable)
|
|
+{
|
|
+ struct device *dev = priv->dev;
|
|
+ uint32_t i;
|
|
+ int flash_cmd;
|
|
+
|
|
+ dev_info(dev, "Region write protection %s: addr=0x%x, size=0x%x\n",
|
|
+ enable ? "enabled" : "disabled", addr, size);
|
|
+
|
|
+ pm_runtime_get_sync(dev);
|
|
+
|
|
+ flash_cmd = enable ? SPINOR_BLOCK_LOCK : SPINOR_BLOCK_UNLOCK;
|
|
+
|
|
+ external_cs_manage(priv, false);
|
|
+
|
|
+ for (i = 0; i < size; i += ALIGNMENT_SIZE) {
|
|
+ eswin_bootspi_write_flash_individual_block_lock_register(priv, addr + i, flash_cmd);
|
|
+ }
|
|
+ external_cs_manage(priv, true);
|
|
+
|
|
+ pm_runtime_put_sync(dev);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static ssize_t region_wp_enable_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ struct es_spi_priv *priv = dev_get_drvdata(dev);
|
|
+ u32 addr, size;
|
|
+ unsigned long enable;
|
|
+ int ret;
|
|
+
|
|
+ // Parsing the input buffer
|
|
+ ret = sscanf(buf, "%x %x %lu", &addr, &size, &enable);
|
|
+ if (ret != 3) {
|
|
+ dev_err(dev, "invalid format %s\n", buf);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Check if the address is 64KB aligned
|
|
+ if ((uintptr_t)addr % ALIGNMENT_SIZE != 0) {
|
|
+ dev_err(dev, "addr 0x%x is not aligned to 64KB\n", addr);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Check if the size is 64KB aligned
|
|
+ if (size % ALIGNMENT_SIZE != 0) {
|
|
+ dev_err(dev, "size 0x%x is not aligned to 64KB\n", size);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Call the region write protection configuration function
|
|
+ eswin_bootspi_region_wp_cfg(priv, addr, size, enable);
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static ssize_t region_wp_enable_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ // This is a placeholder. You may want to display the status of region protection
|
|
+ // For simplicity, we'll return a static message for now.
|
|
+ return sprintf(buf, "Use echo <addr> <size> <enable> > region_wp_enable to configure region WP\n");
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR_RW(region_wp_enable);
|
|
+
|
|
static int eswin_bootspi_exec_op(struct spi_mem *mem,
|
|
const struct spi_mem_op *op)
|
|
{
|
|
@@ -596,7 +727,7 @@ static int eswin_bootspi_exec_op(struct spi_mem *mem,
|
|
|
|
dev_dbg(dev, "[%s %d]: data direction=%d, opcode = 0x%x, cmd_type 0x%x\n",
|
|
__func__,__LINE__, op->data.dir, priv->opcode, priv->cmd_type);
|
|
-
|
|
+/*
|
|
if (priv->wp_enabled) {
|
|
switch(priv->opcode) {
|
|
case SPINOR_OP_BE_4K:
|
|
@@ -614,6 +745,7 @@ static int eswin_bootspi_exec_op(struct spi_mem *mem,
|
|
return -EACCES;
|
|
}
|
|
}
|
|
+*/
|
|
external_cs_manage(priv, false);
|
|
|
|
if (read) {
|
|
@@ -756,6 +888,13 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
return ret;
|
|
}
|
|
|
|
+ // Register the new region_wp_enable attribute
|
|
+ ret = device_create_file(&pdev->dev, &dev_attr_region_wp_enable);
|
|
+ if (ret) {
|
|
+ device_remove_file(&pdev->dev, &dev_attr_wp_enable);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
ret = clk_prepare_enable(priv->cfg_clk);
|
|
if (ret) {
|
|
dev_err(dev, "could not enable cfg clock: %d\n", ret);
|
|
@@ -774,7 +913,6 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
dev_err(dev, "could not enable clock: %d\n", ret);
|
|
goto out_clk;
|
|
}
|
|
-
|
|
pm_runtime_set_autosuspend_delay(dev, 2000);
|
|
pm_runtime_use_autosuspend(dev);
|
|
pm_runtime_get_noresume(dev);
|
|
@@ -785,6 +923,8 @@ static int eswin_bootspi_probe(struct platform_device *pdev)
|
|
if (ret)
|
|
goto out_register_controller;
|
|
|
|
+ eswin_bootspi_wp_cfg(priv, 1);
|
|
+
|
|
pm_runtime_mark_last_busy(dev);
|
|
pm_runtime_put_autosuspend(dev);
|
|
|
|
--
|
|
2.47.0
|
|
|