1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for Intel Camera Imaging ISP subsystem. 4 * Copyright (c) 2010 - 2015, Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 */ 15 16 #include "hmm.h" 17 18 #include "ia_css_types.h" 19 #define __INLINE_SP__ 20 #include "sp.h" 21 22 #include "assert_support.h" 23 #include "ia_css_spctrl.h" 24 #include "ia_css_debug.h" 25 26 struct spctrl_context_info { 27 struct ia_css_sp_init_dmem_cfg dmem_config; 28 u32 spctrl_config_dmem_addr; /* location of dmem_cfg in SP dmem */ 29 u32 spctrl_state_dmem_addr; 30 unsigned int sp_entry; /* entry function ptr on SP */ 31 ia_css_ptr code_addr; /* sp firmware location in host mem-DDR*/ 32 u32 code_size; 33 char *program_name; /* used in case of PLATFORM_SIM */ 34 }; 35 36 static struct spctrl_context_info spctrl_cofig_info[N_SP_ID]; 37 static bool spctrl_loaded[N_SP_ID] = {0}; 38 39 /* Load firmware */ 40 int ia_css_spctrl_load_fw(sp_ID_t sp_id, 41 ia_css_spctrl_cfg *spctrl_cfg) 42 { 43 ia_css_ptr code_addr = mmgr_NULL; 44 struct ia_css_sp_init_dmem_cfg *init_dmem_cfg; 45 46 if ((sp_id >= N_SP_ID) || (!spctrl_cfg)) 47 return -EINVAL; 48 49 spctrl_cofig_info[sp_id].code_addr = mmgr_NULL; 50 51 init_dmem_cfg = &spctrl_cofig_info[sp_id].dmem_config; 52 init_dmem_cfg->dmem_data_addr = spctrl_cfg->dmem_data_addr; 53 init_dmem_cfg->dmem_bss_addr = spctrl_cfg->dmem_bss_addr; 54 init_dmem_cfg->data_size = spctrl_cfg->data_size; 55 init_dmem_cfg->bss_size = spctrl_cfg->bss_size; 56 init_dmem_cfg->sp_id = sp_id; 57 58 spctrl_cofig_info[sp_id].spctrl_config_dmem_addr = 59 spctrl_cfg->spctrl_config_dmem_addr; 60 spctrl_cofig_info[sp_id].spctrl_state_dmem_addr = 61 spctrl_cfg->spctrl_state_dmem_addr; 62 63 /* store code (text + icache) and data to DDR 64 * 65 * Data used to be stored separately, because of access alignment constraints, 66 * fix the FW generation instead 67 */ 68 code_addr = hmm_alloc(spctrl_cfg->code_size, HMM_BO_PRIVATE, 0, NULL, 0); 69 if (code_addr == mmgr_NULL) 70 return -ENOMEM; 71 hmm_store(code_addr, spctrl_cfg->code, spctrl_cfg->code_size); 72 73 if (sizeof(ia_css_ptr) > sizeof(hrt_data)) { 74 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 75 "size of ia_css_ptr can not be greater than hrt_data\n"); 76 hmm_free(code_addr); 77 code_addr = mmgr_NULL; 78 return -EINVAL; 79 } 80 81 init_dmem_cfg->ddr_data_addr = code_addr + spctrl_cfg->ddr_data_offset; 82 if ((init_dmem_cfg->ddr_data_addr % HIVE_ISP_DDR_WORD_BYTES) != 0) { 83 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 84 "DDR address pointer is not properly aligned for DMA transfer\n"); 85 hmm_free(code_addr); 86 code_addr = mmgr_NULL; 87 return -EINVAL; 88 } 89 90 spctrl_cofig_info[sp_id].sp_entry = spctrl_cfg->sp_entry; 91 spctrl_cofig_info[sp_id].code_addr = code_addr; 92 spctrl_cofig_info[sp_id].program_name = spctrl_cfg->program_name; 93 94 /* now we program the base address into the icache and 95 * invalidate the cache. 96 */ 97 sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG, 98 (hrt_data)spctrl_cofig_info[sp_id].code_addr); 99 sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT); 100 spctrl_loaded[sp_id] = true; 101 return 0; 102 } 103 104 /* ISP2401 */ 105 /* reload pre-loaded FW */ 106 void sh_css_spctrl_reload_fw(sp_ID_t sp_id) 107 { 108 /* now we program the base address into the icache and 109 * invalidate the cache. 110 */ 111 sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG, 112 (hrt_data)spctrl_cofig_info[sp_id].code_addr); 113 sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT); 114 spctrl_loaded[sp_id] = true; 115 } 116 117 ia_css_ptr get_sp_code_addr(sp_ID_t sp_id) 118 { 119 return spctrl_cofig_info[sp_id].code_addr; 120 } 121 122 int ia_css_spctrl_unload_fw(sp_ID_t sp_id) 123 { 124 if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id]))) 125 return -EINVAL; 126 127 /* freeup the resource */ 128 if (spctrl_cofig_info[sp_id].code_addr) { 129 hmm_free(spctrl_cofig_info[sp_id].code_addr); 130 spctrl_cofig_info[sp_id].code_addr = mmgr_NULL; 131 } 132 spctrl_loaded[sp_id] = false; 133 return 0; 134 } 135 136 /* Initialize dmem_cfg in SP dmem and start SP program*/ 137 int ia_css_spctrl_start(sp_ID_t sp_id) 138 { 139 if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id]))) 140 return -EINVAL; 141 142 /* Set descr in the SP to initialize the SP DMEM */ 143 /* 144 * The FW stores user-space pointers to the FW, the ISP pointer 145 * is only available here 146 * 147 */ 148 assert(sizeof(unsigned int) <= sizeof(hrt_data)); 149 150 sp_dmem_store(sp_id, 151 spctrl_cofig_info[sp_id].spctrl_config_dmem_addr, 152 &spctrl_cofig_info[sp_id].dmem_config, 153 sizeof(spctrl_cofig_info[sp_id].dmem_config)); 154 /* set the start address */ 155 sp_ctrl_store(sp_id, SP_START_ADDR_REG, 156 (hrt_data)spctrl_cofig_info[sp_id].sp_entry); 157 sp_ctrl_setbit(sp_id, SP_SC_REG, SP_RUN_BIT); 158 sp_ctrl_setbit(sp_id, SP_SC_REG, SP_START_BIT); 159 return 0; 160 } 161 162 /* Query the state of SP1 */ 163 ia_css_spctrl_sp_sw_state ia_css_spctrl_get_state(sp_ID_t sp_id) 164 { 165 ia_css_spctrl_sp_sw_state state = 0; 166 unsigned int HIVE_ADDR_sp_sw_state; 167 168 if (sp_id >= N_SP_ID) 169 return IA_CSS_SP_SW_TERMINATED; 170 171 HIVE_ADDR_sp_sw_state = spctrl_cofig_info[sp_id].spctrl_state_dmem_addr; 172 (void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */ 173 if (sp_id == SP0_ID) 174 state = sp_dmem_load_uint32(sp_id, (unsigned int)sp_address_of(sp_sw_state)); 175 return state; 176 } 177 178 int ia_css_spctrl_is_idle(sp_ID_t sp_id) 179 { 180 int state = 0; 181 182 assert(sp_id < N_SP_ID); 183 184 state = sp_ctrl_getbit(sp_id, SP_SC_REG, SP_IDLE_BIT); 185 return state; 186 } 187