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