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
26struct 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
36static struct spctrl_context_info spctrl_cofig_info[N_SP_ID];
37static bool spctrl_loaded[N_SP_ID] = {0};
38
39/* Load firmware */
40int 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 */
105void 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
116ia_css_ptr get_sp_code_addr(sp_ID_t  sp_id)
117{
118	return spctrl_cofig_info[sp_id].code_addr;
119}
120
121int 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*/
136int 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 */
162ia_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
177int 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