From 25baaf3d5b60f28ae2afd31e199bd9bbd42068cb Mon Sep 17 00:00:00 2001 From: huangyifeng 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 --- 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 > 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