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, ia_css_spctrl_cfg *spctrl_cfg)
41 {
42 	ia_css_ptr code_addr = mmgr_NULL;
43 	struct ia_css_sp_init_dmem_cfg *init_dmem_cfg;
44 
45 	if ((sp_id >= N_SP_ID) || (!spctrl_cfg))
46 		return -EINVAL;
47 
48 	spctrl_cofig_info[sp_id].code_addr = mmgr_NULL;
49 
50 	init_dmem_cfg = &spctrl_cofig_info[sp_id].dmem_config;
51 	init_dmem_cfg->dmem_data_addr = spctrl_cfg->dmem_data_addr;
52 	init_dmem_cfg->dmem_bss_addr  = spctrl_cfg->dmem_bss_addr;
53 	init_dmem_cfg->data_size      = spctrl_cfg->data_size;
54 	init_dmem_cfg->bss_size       = spctrl_cfg->bss_size;
55 	init_dmem_cfg->sp_id          = sp_id;
56 
57 	spctrl_cofig_info[sp_id].spctrl_config_dmem_addr =
58 	    spctrl_cfg->spctrl_config_dmem_addr;
59 	spctrl_cofig_info[sp_id].spctrl_state_dmem_addr =
60 	    spctrl_cfg->spctrl_state_dmem_addr;
61 
62 	/* store code (text + icache) and data to DDR
63 	 *
64 	 * Data used to be stored separately, because of access alignment constraints,
65 	 * fix the FW generation instead
66 	 */
67 	code_addr = hmm_alloc(spctrl_cfg->code_size);
68 	if (code_addr == mmgr_NULL)
69 		return -ENOMEM;
70 	hmm_store(code_addr, spctrl_cfg->code, spctrl_cfg->code_size);
71 
72 	if (sizeof(ia_css_ptr) > sizeof(hrt_data)) {
73 		ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
74 				    "size of ia_css_ptr can not be greater than hrt_data\n");
75 		hmm_free(code_addr);
76 		code_addr = mmgr_NULL;
77 		return -EINVAL;
78 	}
79 
80 	init_dmem_cfg->ddr_data_addr  = code_addr + spctrl_cfg->ddr_data_offset;
81 	if ((init_dmem_cfg->ddr_data_addr % HIVE_ISP_DDR_WORD_BYTES) != 0) {
82 		ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
83 				    "DDR address pointer is not properly aligned for DMA transfer\n");
84 		hmm_free(code_addr);
85 		code_addr = mmgr_NULL;
86 		return -EINVAL;
87 	}
88 
89 	spctrl_cofig_info[sp_id].sp_entry = spctrl_cfg->sp_entry;
90 	spctrl_cofig_info[sp_id].code_addr = code_addr;
91 	spctrl_cofig_info[sp_id].program_name = spctrl_cfg->program_name;
92 
93 	/* now we program the base address into the icache and
94 	 * invalidate the cache.
95 	 */
96 	sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG,
97 		      (hrt_data)spctrl_cofig_info[sp_id].code_addr);
98 	sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT);
99 	spctrl_loaded[sp_id] = true;
100 	return 0;
101 }
102 
103 /* ISP2401 */
104 /* reload pre-loaded FW */
105 void sh_css_spctrl_reload_fw(sp_ID_t sp_id)
106 {
107 	/* now we program the base address into the icache and
108 	 * invalidate the cache.
109 	 */
110 	sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG,
111 		      (hrt_data)spctrl_cofig_info[sp_id].code_addr);
112 	sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT);
113 	spctrl_loaded[sp_id] = true;
114 }
115 
116 ia_css_ptr get_sp_code_addr(sp_ID_t  sp_id)
117 {
118 	return spctrl_cofig_info[sp_id].code_addr;
119 }
120 
121 int ia_css_spctrl_unload_fw(sp_ID_t sp_id)
122 {
123 	if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id])))
124 		return -EINVAL;
125 
126 	/*  freeup the resource */
127 	if (spctrl_cofig_info[sp_id].code_addr) {
128 		hmm_free(spctrl_cofig_info[sp_id].code_addr);
129 		spctrl_cofig_info[sp_id].code_addr = mmgr_NULL;
130 	}
131 	spctrl_loaded[sp_id] = false;
132 	return 0;
133 }
134 
135 /* Initialize dmem_cfg in SP dmem  and  start SP program*/
136 int ia_css_spctrl_start(sp_ID_t sp_id)
137 {
138 	if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id])))
139 		return -EINVAL;
140 
141 	/* Set descr in the SP to initialize the SP DMEM */
142 	/*
143 	 * The FW stores user-space pointers to the FW, the ISP pointer
144 	 * is only available here
145 	 *
146 	 */
147 	assert(sizeof(unsigned int) <= sizeof(hrt_data));
148 
149 	sp_dmem_store(sp_id,
150 		      spctrl_cofig_info[sp_id].spctrl_config_dmem_addr,
151 		      &spctrl_cofig_info[sp_id].dmem_config,
152 		      sizeof(spctrl_cofig_info[sp_id].dmem_config));
153 	/* set the start address */
154 	sp_ctrl_store(sp_id, SP_START_ADDR_REG,
155 		      (hrt_data)spctrl_cofig_info[sp_id].sp_entry);
156 	sp_ctrl_setbit(sp_id, SP_SC_REG, SP_RUN_BIT);
157 	sp_ctrl_setbit(sp_id, SP_SC_REG, SP_START_BIT);
158 	return 0;
159 }
160 
161 /* Query the state of SP1 */
162 ia_css_spctrl_sp_sw_state ia_css_spctrl_get_state(sp_ID_t sp_id)
163 {
164 	ia_css_spctrl_sp_sw_state state = 0;
165 	unsigned int HIVE_ADDR_sp_sw_state;
166 
167 	if (sp_id >= N_SP_ID)
168 		return IA_CSS_SP_SW_TERMINATED;
169 
170 	HIVE_ADDR_sp_sw_state = spctrl_cofig_info[sp_id].spctrl_state_dmem_addr;
171 	(void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */
172 	if (sp_id == SP0_ID)
173 		state = sp_dmem_load_uint32(sp_id, (unsigned int)sp_address_of(sp_sw_state));
174 	return state;
175 }
176 
177 int ia_css_spctrl_is_idle(sp_ID_t sp_id)
178 {
179 	int state = 0;
180 
181 	assert(sp_id < N_SP_ID);
182 
183 	state = sp_ctrl_getbit(sp_id, SP_SC_REG, SP_IDLE_BIT);
184 	return state;
185 }
186