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 "assert_support.h"
17#include "irq.h"
18
19#ifndef __INLINE_GP_DEVICE__
20#define __INLINE_GP_DEVICE__
21#endif
22#include "gp_device.h"	/* _REG_GP_IRQ_REQUEST_ADDR */
23
24static inline void irq_wait_for_write_complete(
25    const irq_ID_t		ID);
26
27static inline bool any_irq_channel_enabled(
28    const irq_ID_t				ID);
29
30static inline irq_ID_t virq_get_irq_id(const enum virq_id irq_ID,
31				       unsigned int *channel_ID);
32
33#ifndef __INLINE_IRQ__
34#include "irq_private.h"
35#endif /* __INLINE_IRQ__ */
36
37static unsigned short IRQ_N_CHANNEL[N_IRQ_ID] = {
38	IRQ0_ID_N_CHANNEL,
39	IRQ1_ID_N_CHANNEL,
40	IRQ2_ID_N_CHANNEL,
41	IRQ3_ID_N_CHANNEL
42};
43
44static unsigned short IRQ_N_ID_OFFSET[N_IRQ_ID + 1] = {
45	IRQ0_ID_OFFSET,
46	IRQ1_ID_OFFSET,
47	IRQ2_ID_OFFSET,
48	IRQ3_ID_OFFSET,
49	IRQ_END_OFFSET
50};
51
52static enum virq_id IRQ_NESTING_ID[N_IRQ_ID] = {
53	N_virq_id,
54	virq_ifmt,
55	virq_isys,
56	virq_isel
57};
58
59void irq_clear_all(
60    const irq_ID_t				ID)
61{
62	hrt_data	mask = 0xFFFFFFFF;
63
64	assert(ID < N_IRQ_ID);
65	assert(IRQ_N_CHANNEL[ID] <= HRT_DATA_WIDTH);
66
67	if (IRQ_N_CHANNEL[ID] < HRT_DATA_WIDTH) {
68		mask = ~((~(hrt_data)0) >> IRQ_N_CHANNEL[ID]);
69	}
70
71	irq_reg_store(ID,
72		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, mask);
73	return;
74}
75
76/*
77 * Do we want the user to be able to set the signalling method ?
78 */
79void irq_enable_channel(
80    const irq_ID_t				ID,
81    const unsigned int			irq_id)
82{
83	unsigned int mask = irq_reg_load(ID,
84					 _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
85	unsigned int enable = irq_reg_load(ID,
86					   _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
87	unsigned int edge_in = irq_reg_load(ID,
88					    _HRT_IRQ_CONTROLLER_EDGE_REG_IDX);
89	unsigned int me = 1U << irq_id;
90
91	assert(ID < N_IRQ_ID);
92	assert(irq_id < IRQ_N_CHANNEL[ID]);
93
94	mask |= me;
95	enable |= me;
96	edge_in |= me;	/* rising edge */
97
98	/* to avoid mishaps configuration must follow the following order */
99
100	/* mask this interrupt */
101	irq_reg_store(ID,
102		      _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask & ~me);
103	/* rising edge at input */
104	irq_reg_store(ID,
105		      _HRT_IRQ_CONTROLLER_EDGE_REG_IDX, edge_in);
106	/* enable interrupt to output */
107	irq_reg_store(ID,
108		      _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, enable);
109	/* clear current irq only */
110	irq_reg_store(ID,
111		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, me);
112	/* unmask interrupt from input */
113	irq_reg_store(ID,
114		      _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask);
115
116	irq_wait_for_write_complete(ID);
117
118	return;
119}
120
121void irq_enable_pulse(
122    const irq_ID_t	ID,
123    bool			pulse)
124{
125	unsigned int edge_out = 0x0;
126
127	if (pulse) {
128		edge_out = 0xffffffff;
129	}
130	/* output is given as edge, not pulse */
131	irq_reg_store(ID,
132		      _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX, edge_out);
133	return;
134}
135
136void irq_disable_channel(
137    const irq_ID_t				ID,
138    const unsigned int			irq_id)
139{
140	unsigned int mask = irq_reg_load(ID,
141					 _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
142	unsigned int enable = irq_reg_load(ID,
143					   _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
144	unsigned int me = 1U << irq_id;
145
146	assert(ID < N_IRQ_ID);
147	assert(irq_id < IRQ_N_CHANNEL[ID]);
148
149	mask &= ~me;
150	enable &= ~me;
151
152	/* enable interrupt to output */
153	irq_reg_store(ID,
154		      _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, enable);
155	/* unmask interrupt from input */
156	irq_reg_store(ID,
157		      _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask);
158	/* clear current irq only */
159	irq_reg_store(ID,
160		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, me);
161
162	irq_wait_for_write_complete(ID);
163
164	return;
165}
166
167enum hrt_isp_css_irq_status irq_get_channel_id(
168    const irq_ID_t				ID,
169    unsigned int				*irq_id)
170{
171	unsigned int irq_status = irq_reg_load(ID,
172					       _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
173	unsigned int idx;
174	enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success;
175
176	assert(ID < N_IRQ_ID);
177	assert(irq_id);
178
179	/* find the first irq bit */
180	for (idx = 0; idx < IRQ_N_CHANNEL[ID]; idx++) {
181		if (irq_status & (1U << idx))
182			break;
183	}
184	if (idx == IRQ_N_CHANNEL[ID])
185		return hrt_isp_css_irq_status_error;
186
187	/* now check whether there are more bits set */
188	if (irq_status != (1U << idx))
189		status = hrt_isp_css_irq_status_more_irqs;
190
191	irq_reg_store(ID,
192		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << idx);
193
194	irq_wait_for_write_complete(ID);
195
196	if (irq_id)
197		*irq_id = (unsigned int)idx;
198
199	return status;
200}
201
202static const hrt_address IRQ_REQUEST_ADDR[N_IRQ_SW_CHANNEL_ID] = {
203	_REG_GP_IRQ_REQUEST0_ADDR,
204	_REG_GP_IRQ_REQUEST1_ADDR
205};
206
207void irq_raise(
208    const irq_ID_t				ID,
209    const irq_sw_channel_id_t	irq_id)
210{
211	hrt_address		addr;
212
213	OP___assert(ID == IRQ0_ID);
214	OP___assert(IRQ_BASE[ID] != (hrt_address)-1);
215	OP___assert(irq_id < N_IRQ_SW_CHANNEL_ID);
216
217	(void)ID;
218
219	addr = IRQ_REQUEST_ADDR[irq_id];
220	/* The SW IRQ pins are remapped to offset zero */
221	gp_device_reg_store(GP_DEVICE0_ID,
222			    (unsigned int)addr, 1);
223	gp_device_reg_store(GP_DEVICE0_ID,
224			    (unsigned int)addr, 0);
225	return;
226}
227
228bool any_virq_signal(void)
229{
230	unsigned int irq_status = irq_reg_load(IRQ0_ID,
231					       _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
232
233	return (irq_status != 0);
234}
235
236void cnd_virq_enable_channel(
237    const enum virq_id				irq_ID,
238    const bool					en)
239{
240	irq_ID_t		i;
241	unsigned int	channel_ID;
242	irq_ID_t		ID = virq_get_irq_id(irq_ID, &channel_ID);
243
244	assert(ID < N_IRQ_ID);
245
246	for (i = IRQ1_ID; i < N_IRQ_ID; i++) {
247		/* It is not allowed to enable the pin of a nested IRQ directly */
248		assert(irq_ID != IRQ_NESTING_ID[i]);
249	}
250
251	if (en) {
252		irq_enable_channel(ID, channel_ID);
253		if (IRQ_NESTING_ID[ID] != N_virq_id) {
254			/* Single level nesting, otherwise we'd need to recurse */
255			irq_enable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]);
256		}
257	} else {
258		irq_disable_channel(ID, channel_ID);
259		if ((IRQ_NESTING_ID[ID] != N_virq_id) && !any_irq_channel_enabled(ID)) {
260			/* Only disable the top if the nested ones are empty */
261			irq_disable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]);
262		}
263	}
264	return;
265}
266
267void virq_clear_all(void)
268{
269	irq_ID_t	irq_id;
270
271	for (irq_id = (irq_ID_t)0; irq_id < N_IRQ_ID; irq_id++) {
272		irq_clear_all(irq_id);
273	}
274	return;
275}
276
277enum hrt_isp_css_irq_status
278virq_get_channel_signals(struct virq_info *irq_info)
279{
280	enum hrt_isp_css_irq_status irq_status = hrt_isp_css_irq_status_error;
281	irq_ID_t ID;
282
283	assert(irq_info);
284
285	for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
286		if (any_irq_channel_enabled(ID)) {
287			hrt_data	irq_data = irq_reg_load(ID,
288							    _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
289
290			if (irq_data != 0) {
291				/* The error condition is an IRQ pulse received with no IRQ status written */
292				irq_status = hrt_isp_css_irq_status_success;
293			}
294
295			irq_info->irq_status_reg[ID] |= irq_data;
296
297			irq_reg_store(ID,
298				      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, irq_data);
299
300			irq_wait_for_write_complete(ID);
301		}
302	}
303
304	return irq_status;
305}
306
307void virq_clear_info(struct virq_info *irq_info)
308{
309	irq_ID_t ID;
310
311	assert(irq_info);
312
313	for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
314		irq_info->irq_status_reg[ID] = 0;
315	}
316	return;
317}
318
319enum hrt_isp_css_irq_status virq_get_channel_id(
320    enum virq_id					*irq_id)
321{
322	unsigned int irq_status = irq_reg_load(IRQ0_ID,
323					       _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
324	unsigned int idx;
325	enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success;
326	irq_ID_t ID;
327
328	assert(irq_id);
329
330	/* find the first irq bit on device 0 */
331	for (idx = 0; idx < IRQ_N_CHANNEL[IRQ0_ID]; idx++) {
332		if (irq_status & (1U << idx))
333			break;
334	}
335
336	if (idx == IRQ_N_CHANNEL[IRQ0_ID]) {
337		return hrt_isp_css_irq_status_error;
338	}
339
340	/* Check whether there are more bits set on device 0 */
341	if (irq_status != (1U << idx)) {
342		status = hrt_isp_css_irq_status_more_irqs;
343	}
344
345	/* Check whether we have an IRQ on one of the nested devices */
346	for (ID = N_IRQ_ID - 1 ; ID > (irq_ID_t)0; ID--) {
347		if (IRQ_NESTING_ID[ID] == (enum virq_id)idx) {
348			break;
349		}
350	}
351
352	/* If we have a nested IRQ, load that state, discard the device 0 state */
353	if (ID != IRQ0_ID) {
354		irq_status = irq_reg_load(ID,
355					  _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
356		/* find the first irq bit on device "id" */
357		for (idx = 0; idx < IRQ_N_CHANNEL[ID]; idx++) {
358			if (irq_status & (1U << idx))
359				break;
360		}
361
362		if (idx == IRQ_N_CHANNEL[ID]) {
363			return hrt_isp_css_irq_status_error;
364		}
365
366		/* Alternatively check whether there are more bits set on this device */
367		if (irq_status != (1U << idx)) {
368			status = hrt_isp_css_irq_status_more_irqs;
369		} else {
370			/* If this device is empty, clear the state on device 0 */
371			irq_reg_store(IRQ0_ID,
372				      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << IRQ_NESTING_ID[ID]);
373		}
374	} /* if (ID != IRQ0_ID) */
375
376	/* Here we proceed to clear the IRQ on detected device, if no nested IRQ, this is device 0 */
377	irq_reg_store(ID,
378		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << idx);
379
380	irq_wait_for_write_complete(ID);
381
382	idx += IRQ_N_ID_OFFSET[ID];
383	if (irq_id)
384		*irq_id = (enum virq_id)idx;
385
386	return status;
387}
388
389static inline void irq_wait_for_write_complete(
390    const irq_ID_t		ID)
391{
392	assert(ID < N_IRQ_ID);
393	assert(IRQ_BASE[ID] != (hrt_address)-1);
394	(void)ia_css_device_load_uint32(IRQ_BASE[ID] +
395					_HRT_IRQ_CONTROLLER_ENABLE_REG_IDX * sizeof(hrt_data));
396}
397
398static inline bool any_irq_channel_enabled(
399    const irq_ID_t				ID)
400{
401	hrt_data	en_reg;
402
403	assert(ID < N_IRQ_ID);
404
405	en_reg = irq_reg_load(ID,
406			      _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
407
408	return (en_reg != 0);
409}
410
411static inline irq_ID_t virq_get_irq_id(
412    const enum virq_id		irq_ID,
413    unsigned int		*channel_ID)
414{
415	irq_ID_t ID;
416
417	assert(channel_ID);
418
419	for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
420		if (irq_ID < IRQ_N_ID_OFFSET[ID + 1]) {
421			break;
422		}
423	}
424
425	*channel_ID = (unsigned int)irq_ID - IRQ_N_ID_OFFSET[ID];
426
427	return ID;
428}
429