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