/* * Copyright (c) 2024 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #ifdef CONFIG_USERSPACE #include #include #endif #include #include "flash_hp_ra.h" #define FLASH_HP_CONFIG_SET_ACCESS_WORD_CNT (8U) #if (DT_PROP(DT_NODELABEL(flash0), renesas_programming_enable)) extern uint16_t g_configuration_area_data[FLASH_HP_CONFIG_SET_ACCESS_WORD_CNT]; #endif extern fsp_err_t flash_hp_enter_pe_cf_mode(flash_hp_instance_ctrl_t *const p_ctrl) PLACE_IN_RAM_SECTION; extern fsp_err_t flash_hp_stop(void) PLACE_IN_RAM_SECTION; extern fsp_err_t flash_hp_configuration_area_write(flash_hp_instance_ctrl_t *p_ctrl, uint32_t fsaddr) PLACE_IN_RAM_SECTION; extern fsp_err_t flash_hp_check_errors(fsp_err_t previous_error, uint32_t error_bits, fsp_err_t return_error) PLACE_IN_RAM_SECTION; extern fsp_err_t flash_hp_pe_mode_exit(void) PLACE_IN_RAM_SECTION; static fsp_err_t flash_hp_set_block_protect_ns(flash_hp_instance_ctrl_t *p_ctrl, uint8_t *bps_val_ns, uint8_t *pbps_val_ns, uint32_t size) PLACE_IN_RAM_SECTION; static fsp_err_t flash_hp_set_block_protect_sec(flash_hp_instance_ctrl_t *p_ctrl, uint8_t *bps_val_sec, uint8_t *pbps_val_sec, uint32_t size) PLACE_IN_RAM_SECTION; static fsp_err_t flash_hp_set_block_protect_sel(flash_hp_instance_ctrl_t *p_ctrl, uint8_t *bps_sel_val, uint32_t size) PLACE_IN_RAM_SECTION; static fsp_err_t flash_hp_set_block_protect_ns(flash_hp_instance_ctrl_t *p_ctrl, uint8_t *bps_val_ns, uint8_t *pbps_val_ns, uint32_t size) { /* Disable interrupts to prevent vector table access while code flash is in P/E mode. */ int key = irq_lock(); /* Update Flash state and enter Code Flash P/E mode */ fsp_err_t err = flash_hp_enter_pe_cf_mode(p_ctrl); FSP_ERROR_RETURN(err == FSP_SUCCESS, err); memset(g_configuration_area_data, UINT8_MAX, sizeof(g_configuration_area_data)); if (bps_val_ns != NULL) { memcpy(&g_configuration_area_data[FLASH_HP_FCU_CONFIG_SET_BPS_OFFSET], bps_val_ns, size); err = flash_hp_configuration_area_write(p_ctrl, FLASH_HP_FCU_CONFIG_SET_BPS); err = flash_hp_check_errors(err, 0, FSP_ERR_WRITE_FAILED); } memset(g_configuration_area_data, UINT8_MAX, sizeof(g_configuration_area_data)); if (pbps_val_ns != NULL) { memcpy(&g_configuration_area_data[FLASH_HP_FCU_CONFIG_SET_BPS_OFFSET], pbps_val_ns, size); err = flash_hp_configuration_area_write(p_ctrl, FLASH_HP_FCU_CONFIG_SET_PBPS); err = flash_hp_check_errors(err, 0, FSP_ERR_WRITE_FAILED); } /* Return to read mode*/ fsp_err_t pe_exit_err = flash_hp_pe_mode_exit(); if (err == FSP_SUCCESS) { err = pe_exit_err; } /* Enable interrupts after code flash operations are complete. */ irq_unlock(key); return err; } static fsp_err_t flash_hp_set_block_protect_sec(flash_hp_instance_ctrl_t *p_ctrl, uint8_t *bps_val_sec, uint8_t *pbps_val_sec, uint32_t size) { /* Disable interrupts to prevent vector table access while code flash is in P/E mode. */ int key = irq_lock(); /* Update Flash state and enter Code Flash P/E mode */ fsp_err_t err = flash_hp_enter_pe_cf_mode(p_ctrl); FSP_ERROR_RETURN(err == FSP_SUCCESS, err); memset(g_configuration_area_data, UINT8_MAX, sizeof(g_configuration_area_data)); if (bps_val_sec != NULL) { memcpy(&g_configuration_area_data[FLASH_HP_FCU_CONFIG_SET_BPS_OFFSET], bps_val_sec, size); err = flash_hp_configuration_area_write(p_ctrl, FLASH_HP_FCU_CONFIG_SET_BPS_SEC); err = flash_hp_check_errors(err, 0, FSP_ERR_WRITE_FAILED); } memset(g_configuration_area_data, UINT8_MAX, sizeof(g_configuration_area_data)); if (pbps_val_sec != NULL) { memcpy(&g_configuration_area_data[FLASH_HP_FCU_CONFIG_SET_BPS_OFFSET], pbps_val_sec, size); err = flash_hp_configuration_area_write(p_ctrl, FLASH_HP_FCU_CONFIG_SET_PBPS_SEC); err = flash_hp_check_errors(err, 0, FSP_ERR_WRITE_FAILED); } /* Return to read mode*/ fsp_err_t pe_exit_err = flash_hp_pe_mode_exit(); if (err == FSP_SUCCESS) { err = pe_exit_err; } /* Enable interrupts after code flash operations are complete. */ irq_unlock(key); return err; } static fsp_err_t flash_hp_set_block_protect_sel(flash_hp_instance_ctrl_t *p_ctrl, uint8_t *bps_sel_val, uint32_t size) { /* Disable interrupts to prevent vector table access while code flash is in P/E mode. */ int key = irq_lock(); /* Update Flash state and enter Code Flash P/E mode */ fsp_err_t err = flash_hp_enter_pe_cf_mode(p_ctrl); FSP_ERROR_RETURN(err == FSP_SUCCESS, err); memset(g_configuration_area_data, UINT8_MAX, sizeof(g_configuration_area_data)); memcpy(&g_configuration_area_data[FLASH_HP_FCU_CONFIG_SET_BPS_OFFSET], bps_sel_val, size); err = flash_hp_configuration_area_write(p_ctrl, FLASH_HP_FCU_CONFIG_SET_BPS_SEL); err = flash_hp_check_errors(err, 0, FSP_ERR_WRITE_FAILED); /* Return to read mode*/ fsp_err_t pe_exit_err = flash_hp_pe_mode_exit(); if (err == FSP_SUCCESS) { err = pe_exit_err; } /* Enable interrupts after code flash operations are complete. */ irq_unlock(key); return err; } static fsp_err_t R_FLASH_HP_BlockProtectSet(flash_ctrl_t *const p_api_ctrl, uint8_t *bps_val_ns, uint8_t *bps_val_sec, uint8_t *bps_val_sel, uint8_t *pbps_val_ns, uint8_t *pbps_val_sec, uint32_t size); static fsp_err_t R_FLASH_HP_BlockProtectGet(flash_ctrl_t *const p_api_ctrl, uint32_t *bps_val_ns, uint32_t *bps_val_sec, uint8_t *bps_val_sel, uint8_t *pbps_val_ns, uint8_t *pbps_val_sec, uint32_t *size); int flash_ra_block_protect_set(const struct device *dev, const struct flash_ra_ex_write_protect_in *request); int flash_ra_block_protect_get(const struct device *dev, struct flash_ra_ex_write_protect_out *response); static fsp_err_t R_FLASH_HP_BlockProtectSet(flash_ctrl_t *const p_api_ctrl, uint8_t *bps_val_ns, uint8_t *bps_val_sec, uint8_t *bps_val_sel, uint8_t *pbps_val_ns, uint8_t *pbps_val_sec, uint32_t size) { flash_hp_instance_ctrl_t *p_ctrl = (flash_hp_instance_ctrl_t *)p_api_ctrl; fsp_err_t err = FSP_SUCCESS; #if (DT_PROP(DT_NODELABEL(flash0), renesas_programming_enable)) /* if non-secure BPS (PBPS) buffers are not null and size is smaller than 16 bytes */ if (((bps_val_ns != NULL) || (pbps_val_ns != NULL)) && (size <= (sizeof(uint16_t) * FLASH_HP_CONFIG_SET_ACCESS_WORD_CNT))) { err = flash_hp_set_block_protect_ns(p_ctrl, bps_val_ns, pbps_val_ns, size); } /* if secure BPS (PBPS) buffers are not null and size is smaller than 16 bytes */ if (((bps_val_sec != NULL) || (pbps_val_sec != NULL)) && (size <= (sizeof(uint16_t) * FLASH_HP_CONFIG_SET_ACCESS_WORD_CNT))) { err = flash_hp_set_block_protect_sec(p_ctrl, bps_val_sec, pbps_val_sec, size); } /* if BPS SEL buffer is not null and size is smaller than 16 bytes */ if ((bps_val_sel != NULL) && (size <= (sizeof(uint16_t) * FLASH_HP_CONFIG_SET_ACCESS_WORD_CNT))) { err = flash_hp_set_block_protect_sel(p_ctrl, bps_val_sel, size); } #else err = FSP_ERR_UNSUPPORTED; /* For consistency with _LP API we return error if Code Flash */ #endif return err; } static fsp_err_t R_FLASH_HP_BlockProtectGet(flash_ctrl_t *const p_api_ctrl, uint32_t *bps_val_ns, uint32_t *bps_val_sec, uint8_t *bps_val_sel, uint8_t *pbps_val_ns, uint8_t *pbps_val_sec, uint32_t *size) { fsp_err_t err = FSP_ERR_UNSUPPORTED; #if (DT_PROP(DT_NODELABEL(flash0), renesas_programming_enable)) err = FSP_SUCCESS; if (bps_val_ns != NULL) { bps_val_ns[0] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS + 0)); bps_val_ns[1] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS + 3)); bps_val_ns[2] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS + 7)); bps_val_ns[3] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS + 11)); } if (bps_val_sec != NULL) { bps_val_sec[0] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEC + 0)); bps_val_sec[1] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEC + 3)); bps_val_sec[2] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEC + 7)); bps_val_sec[3] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEC + 11)); } if (bps_val_sel != NULL) { bps_val_sel[0] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEL + 0)); bps_val_sel[1] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEL + 3)); bps_val_sel[2] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEL + 7)); bps_val_sel[3] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_BPS_SEL + 11)); } if (pbps_val_ns != NULL) { pbps_val_ns[0] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS + 0)); pbps_val_ns[1] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS + 3)); pbps_val_ns[2] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS + 7)); pbps_val_ns[3] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS + 11)); } if (pbps_val_sec != NULL) { pbps_val_sec[0] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS_SEC + 0)); pbps_val_sec[1] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS_SEC + 3)); pbps_val_sec[2] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS_SEC + 7)); pbps_val_sec[3] = *((uint32_t *)(FLASH_HP_FCU_CONFIG_SET_PBPS_SEC + 11)); } if (size != NULL) { *size = 4; } #endif FSP_PARAMETER_NOT_USED(p_api_ctrl); return err; } #if defined(CONFIG_FLASH_RA_WRITE_PROTECT) int flash_ra_block_protect_get(const struct device *dev, struct flash_ra_ex_write_protect_out *response) { fsp_err_t err = FSP_ERR_ASSERTION; struct flash_hp_ra_data *flash_data = dev->data; struct flash_hp_ra_controller *dev_ctrl = flash_data->controller; flash_ra_cf_block_map bps_ns; /* get the current non-secure BPS register values */ err = R_FLASH_HP_BlockProtectGet(&dev_ctrl->flash_ctrl, (uint32_t *)&bps_ns, NULL, NULL, NULL, NULL, NULL); memcpy(&response->protected_enabled, &bps_ns, sizeof(flash_ra_cf_block_map)); return err; } int flash_ra_ex_op_write_protect(const struct device *dev, const uintptr_t in, void *out) { const struct flash_ra_ex_write_protect_in *request = (const struct flash_ra_ex_write_protect_in *)in; struct flash_ra_ex_write_protect_out *result = (struct flash_ra_ex_write_protect_out *)out; int rc = 0, rc2 = 0; #ifdef CONFIG_USERSPACE bool syscall_trap = z_syscall_trap(); #endif if (request != NULL) { #ifdef CONFIG_USERSPACE struct flash_ra_ex_write_protect_in copy_in; if (syscall_trap) { Z_OOPS(z_user_from_copy(©_in, request, sizeof(copy_in))); request = ©_in; } #endif /* if both enable and disable are set */ if ((request->protect_enable.BPS[0] & request->protect_disable.BPS[0]) || (request->protect_enable.BPS[1] & request->protect_disable.BPS[1]) || (request->protect_enable.BPS[2] & request->protect_disable.BPS[2]) || (request->protect_enable.BPS[3] & request->protect_disable.BPS[3])) { return EINVAL; } rc = flash_ra_block_protect_set(dev, request); } if (result != NULL) { #ifdef CONFIG_USERSPACE struct flash_ra_ex_write_protect_out copy_out; if (syscall_trap) { result = ©_out; } #endif rc2 = flash_ra_block_protect_get(dev, result); if (!rc) { rc = rc2; } #ifdef CONFIG_USERSPACE if (syscall_trap) { Z_OOPS(z_user_to_copy(out, result, sizeof(copy_out))); } #endif } return rc; } int flash_ra_block_protect_set(const struct device *dev, const struct flash_ra_ex_write_protect_in *request) { fsp_err_t err = FSP_ERR_ASSERTION; struct flash_hp_ra_data *flash_data = dev->data; struct flash_hp_ra_controller *dev_ctrl = flash_data->controller; flash_ra_cf_block_map bps_ns; /* get the current non-secure BPS register values */ err = R_FLASH_HP_BlockProtectGet(&dev_ctrl->flash_ctrl, (uint32_t *)&bps_ns, NULL, NULL, NULL, NULL, NULL); if (err != FSP_SUCCESS) { __ASSERT(false, "flash: block get current value error =%d", err); return -EIO; } /* enable block protect */ bps_ns.BPS[0] &= ~(request->protect_enable.BPS[0]); bps_ns.BPS[1] &= ~(request->protect_enable.BPS[1]); bps_ns.BPS[2] &= ~(request->protect_enable.BPS[2]); bps_ns.BPS[3] &= ~(request->protect_enable.BPS[3]); /* disable block protect */ bps_ns.BPS[0] |= (request->protect_disable.BPS[0]); bps_ns.BPS[1] |= (request->protect_disable.BPS[1]); bps_ns.BPS[2] |= (request->protect_disable.BPS[2]); bps_ns.BPS[3] |= (request->protect_disable.BPS[3]); /* reset default all from non-secure */ err = R_FLASH_HP_BlockProtectSet(&dev_ctrl->flash_ctrl, (uint8_t *)&bps_ns, NULL, NULL, NULL, NULL, sizeof(bps_ns)); if (err != FSP_SUCCESS) { __ASSERT(false, "flash: block protect error=%d", err); return -EIO; } return 0; } #endif /* CONFIG_FLASH_RA_WRITE_PROTECT */