// SPDX-License-Identifier: GPL-2.0
|
/*
|
* Support for Intel Camera Imaging ISP subsystem.
|
* Copyright (c) 2010 - 2015, Intel Corporation.
|
*
|
* This program is free software; you can redistribute it and/or modify it
|
* under the terms and conditions of the GNU General Public License,
|
* version 2, as published by the Free Software Foundation.
|
*
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* more details.
|
*/
|
|
#include "hmm.h"
|
|
#include "ia_css_types.h"
|
#define __INLINE_SP__
|
#include "sp.h"
|
|
#include "assert_support.h"
|
#include "ia_css_spctrl.h"
|
#include "ia_css_debug.h"
|
|
struct spctrl_context_info {
|
struct ia_css_sp_init_dmem_cfg dmem_config;
|
u32 spctrl_config_dmem_addr; /* location of dmem_cfg in SP dmem */
|
u32 spctrl_state_dmem_addr;
|
unsigned int sp_entry; /* entry function ptr on SP */
|
ia_css_ptr code_addr; /* sp firmware location in host mem-DDR*/
|
u32 code_size;
|
char *program_name; /* used in case of PLATFORM_SIM */
|
};
|
|
static struct spctrl_context_info spctrl_cofig_info[N_SP_ID];
|
static bool spctrl_loaded[N_SP_ID] = {0};
|
|
/* Load firmware */
|
int ia_css_spctrl_load_fw(sp_ID_t sp_id,
|
ia_css_spctrl_cfg *spctrl_cfg)
|
{
|
ia_css_ptr code_addr = mmgr_NULL;
|
struct ia_css_sp_init_dmem_cfg *init_dmem_cfg;
|
|
if ((sp_id >= N_SP_ID) || (!spctrl_cfg))
|
return -EINVAL;
|
|
spctrl_cofig_info[sp_id].code_addr = mmgr_NULL;
|
|
init_dmem_cfg = &spctrl_cofig_info[sp_id].dmem_config;
|
init_dmem_cfg->dmem_data_addr = spctrl_cfg->dmem_data_addr;
|
init_dmem_cfg->dmem_bss_addr = spctrl_cfg->dmem_bss_addr;
|
init_dmem_cfg->data_size = spctrl_cfg->data_size;
|
init_dmem_cfg->bss_size = spctrl_cfg->bss_size;
|
init_dmem_cfg->sp_id = sp_id;
|
|
spctrl_cofig_info[sp_id].spctrl_config_dmem_addr =
|
spctrl_cfg->spctrl_config_dmem_addr;
|
spctrl_cofig_info[sp_id].spctrl_state_dmem_addr =
|
spctrl_cfg->spctrl_state_dmem_addr;
|
|
/* store code (text + icache) and data to DDR
|
*
|
* Data used to be stored separately, because of access alignment constraints,
|
* fix the FW generation instead
|
*/
|
code_addr = hmm_alloc(spctrl_cfg->code_size, HMM_BO_PRIVATE, 0, NULL, 0);
|
if (code_addr == mmgr_NULL)
|
return -ENOMEM;
|
hmm_store(code_addr, spctrl_cfg->code, spctrl_cfg->code_size);
|
|
if (sizeof(ia_css_ptr) > sizeof(hrt_data)) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
|
"size of ia_css_ptr can not be greater than hrt_data\n");
|
hmm_free(code_addr);
|
code_addr = mmgr_NULL;
|
return -EINVAL;
|
}
|
|
init_dmem_cfg->ddr_data_addr = code_addr + spctrl_cfg->ddr_data_offset;
|
if ((init_dmem_cfg->ddr_data_addr % HIVE_ISP_DDR_WORD_BYTES) != 0) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
|
"DDR address pointer is not properly aligned for DMA transfer\n");
|
hmm_free(code_addr);
|
code_addr = mmgr_NULL;
|
return -EINVAL;
|
}
|
|
spctrl_cofig_info[sp_id].sp_entry = spctrl_cfg->sp_entry;
|
spctrl_cofig_info[sp_id].code_addr = code_addr;
|
spctrl_cofig_info[sp_id].program_name = spctrl_cfg->program_name;
|
|
/* now we program the base address into the icache and
|
* invalidate the cache.
|
*/
|
sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG,
|
(hrt_data)spctrl_cofig_info[sp_id].code_addr);
|
sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT);
|
spctrl_loaded[sp_id] = true;
|
return 0;
|
}
|
|
/* ISP2401 */
|
/* reload pre-loaded FW */
|
void sh_css_spctrl_reload_fw(sp_ID_t sp_id)
|
{
|
/* now we program the base address into the icache and
|
* invalidate the cache.
|
*/
|
sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG,
|
(hrt_data)spctrl_cofig_info[sp_id].code_addr);
|
sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT);
|
spctrl_loaded[sp_id] = true;
|
}
|
|
ia_css_ptr get_sp_code_addr(sp_ID_t sp_id)
|
{
|
return spctrl_cofig_info[sp_id].code_addr;
|
}
|
|
int ia_css_spctrl_unload_fw(sp_ID_t sp_id)
|
{
|
if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id])))
|
return -EINVAL;
|
|
/* freeup the resource */
|
if (spctrl_cofig_info[sp_id].code_addr) {
|
hmm_free(spctrl_cofig_info[sp_id].code_addr);
|
spctrl_cofig_info[sp_id].code_addr = mmgr_NULL;
|
}
|
spctrl_loaded[sp_id] = false;
|
return 0;
|
}
|
|
/* Initialize dmem_cfg in SP dmem and start SP program*/
|
int ia_css_spctrl_start(sp_ID_t sp_id)
|
{
|
if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id])))
|
return -EINVAL;
|
|
/* Set descr in the SP to initialize the SP DMEM */
|
/*
|
* The FW stores user-space pointers to the FW, the ISP pointer
|
* is only available here
|
*
|
*/
|
assert(sizeof(unsigned int) <= sizeof(hrt_data));
|
|
sp_dmem_store(sp_id,
|
spctrl_cofig_info[sp_id].spctrl_config_dmem_addr,
|
&spctrl_cofig_info[sp_id].dmem_config,
|
sizeof(spctrl_cofig_info[sp_id].dmem_config));
|
/* set the start address */
|
sp_ctrl_store(sp_id, SP_START_ADDR_REG,
|
(hrt_data)spctrl_cofig_info[sp_id].sp_entry);
|
sp_ctrl_setbit(sp_id, SP_SC_REG, SP_RUN_BIT);
|
sp_ctrl_setbit(sp_id, SP_SC_REG, SP_START_BIT);
|
return 0;
|
}
|
|
/* Query the state of SP1 */
|
ia_css_spctrl_sp_sw_state ia_css_spctrl_get_state(sp_ID_t sp_id)
|
{
|
ia_css_spctrl_sp_sw_state state = 0;
|
unsigned int HIVE_ADDR_sp_sw_state;
|
|
if (sp_id >= N_SP_ID)
|
return IA_CSS_SP_SW_TERMINATED;
|
|
HIVE_ADDR_sp_sw_state = spctrl_cofig_info[sp_id].spctrl_state_dmem_addr;
|
(void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */
|
if (sp_id == SP0_ID)
|
state = sp_dmem_load_uint32(sp_id, (unsigned int)sp_address_of(sp_sw_state));
|
return state;
|
}
|
|
int ia_css_spctrl_is_idle(sp_ID_t sp_id)
|
{
|
int state = 0;
|
|
assert(sp_id < N_SP_ID);
|
|
state = sp_ctrl_getbit(sp_id, SP_SC_REG, SP_IDLE_BIT);
|
return state;
|
}
|