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 */
ia_css_spctrl_load_fw(sp_ID_t sp_id,ia_css_spctrl_cfg * spctrl_cfg)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 */
sh_css_spctrl_reload_fw(sp_ID_t sp_id)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
get_sp_code_addr(sp_ID_t sp_id)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
ia_css_spctrl_unload_fw(sp_ID_t sp_id)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*/
ia_css_spctrl_start(sp_ID_t sp_id)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 */
ia_css_spctrl_get_state(sp_ID_t sp_id)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
ia_css_spctrl_is_idle(sp_ID_t sp_id)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