Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
6654d17e
Commit
6654d17e
authored
Mar 11, 2020
by
Mark Dykes
Committed by
TrustedFirmware Code Review
Mar 11, 2020
Browse files
Merge "TF-A GICv3 driver: Separate GICD and GICR accessor functions" into integration
parents
9f41b0b1
6e19bd56
Changes
22
Hide whitespace changes
Inline
Side-by-side
drivers/arm/gic/v3/gicdv3_helpers.c
0 → 100644
View file @
6654d17e
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include "gicv3_private.h"
/*******************************************************************************
* GIC Distributor interface accessors for bit operations
******************************************************************************/
/*
* Accessor to read the GIC Distributor IGRPMODR corresponding to the
* interrupt `id`, 32 interrupt IDs at a time.
*/
uint32_t
gicd_read_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
return
GICD_READ
(
IGRPMODR
,
base
,
id
);
}
/*
* Accessor to write the GIC Distributor IGRPMODR corresponding to the
* interrupt `id`, 32 interrupt IDs at a time.
*/
void
gicd_write_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
,
uint32_t
val
)
{
GICD_WRITE
(
IGRPMODR
,
base
,
id
,
val
);
}
/*
* Accessor to get the bit corresponding to interrupt ID
* in GIC Distributor IGRPMODR.
*/
unsigned
int
gicd_get_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
return
GICD_GET_BIT
(
IGRPMODR
,
base
,
id
);
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Distributor IGRPMODR.
*/
void
gicd_set_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
GICD_SET_BIT
(
IGRPMODR
,
base
,
id
);
}
/*
* Accessor to clear the bit corresponding to interrupt ID
* in GIC Distributor IGRPMODR.
*/
void
gicd_clr_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
GICD_CLR_BIT
(
IGRPMODR
,
base
,
id
);
}
drivers/arm/gic/v3/gicrv3_helpers.c
0 → 100644
View file @
6654d17e
/*
* Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/interrupt_props.h>
#include <drivers/arm/gicv3.h>
#include "gicv3_private.h"
/*******************************************************************************
* GIC Redistributor functions
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
******************************************************************************/
/*
* Accessor to read the GIC Redistributor IPRIORITYR corresponding to the
* interrupt `id`, 4 interrupts IDs at a time.
*/
unsigned
int
gicr_read_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
n
=
id
>>
IPRIORITYR_SHIFT
;
return
mmio_read_32
(
base
+
GICR_IPRIORITYR
+
(
n
<<
2
));
}
/*
* Accessor to write the GIC Redistributor IPRIORITYR corresponding to the
* interrupt `id`, 4 interrupts IDs at a time.
*/
void
gicr_write_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
val
)
{
unsigned
int
n
=
id
>>
IPRIORITYR_SHIFT
;
mmio_write_32
(
base
+
GICR_IPRIORITYR
+
(
n
<<
2
),
val
);
}
/*
* Accessor to set the byte corresponding to interrupt ID
* in GIC Redistributor IPRIORITYR.
*/
void
gicr_set_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
pri
)
{
GICR_WRITE_8
(
IPRIORITYR
,
base
,
id
,
pri
&
GIC_PRI_MASK
);
}
/*
* Accessor to get the bit corresponding to interrupt ID
* from GIC Redistributor IGROUPR0.
*/
unsigned
int
gicr_get_igroupr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGROUPR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igroupr0
(
base
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Redistributor IGROUPR0.
*/
void
gicr_set_igroupr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGROUPR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igroupr0
(
base
);
gicr_write_igroupr0
(
base
,
reg_val
|
(
1U
<<
bit_num
));
}
/*
* Accessor to clear the bit corresponding to interrupt ID
* in GIC Redistributor IGROUPR0.
*/
void
gicr_clr_igroupr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGROUPR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igroupr0
(
base
);
gicr_write_igroupr0
(
base
,
reg_val
&
~
(
1U
<<
bit_num
));
}
/*
* Accessor to get the bit corresponding to interrupt ID
* from GIC Redistributor IGRPMODR0.
*/
unsigned
int
gicr_get_igrpmodr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igrpmodr0
(
base
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Redistributor IGRPMODR0.
*/
void
gicr_set_igrpmodr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igrpmodr0
(
base
);
gicr_write_igrpmodr0
(
base
,
reg_val
|
(
1U
<<
bit_num
));
}
/*
* Accessor to clear the bit corresponding to interrupt ID
* in GIC Redistributor IGRPMODR0.
*/
void
gicr_clr_igrpmodr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igrpmodr0
(
base
);
gicr_write_igrpmodr0
(
base
,
reg_val
&
~
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Redistributor ISENABLER0.
*/
void
gicr_set_isenabler0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ISENABLER_SHIFT
)
-
1U
);
gicr_write_isenabler0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID in GIC Redistributor
* ICENABLER0.
*/
void
gicr_set_icenabler0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ICENABLER_SHIFT
)
-
1U
);
gicr_write_icenabler0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID in GIC Redistributor
* ISACTIVER0.
*/
unsigned
int
gicr_get_isactiver0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ISACTIVER_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_isactiver0
(
base
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to clear the bit corresponding to interrupt ID in GIC Redistributor
* ICPENDRR0.
*/
void
gicr_set_icpendr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ICPENDR_SHIFT
)
-
1U
);
gicr_write_icpendr0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID in GIC Redistributor
* ISPENDR0.
*/
void
gicr_set_ispendr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ISPENDR_SHIFT
)
-
1U
);
gicr_write_ispendr0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit fields corresponding to interrupt ID
* in GIC Redistributor ICFGR0.
*/
void
gicr_set_icfgr0
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
cfg
)
{
/* Interrupt configuration is a 2-bit field */
unsigned
int
bit_num
=
id
&
((
1U
<<
ICFGR_SHIFT
)
-
1U
);
unsigned
int
bit_shift
=
bit_num
<<
1U
;
uint32_t
reg_val
=
gicr_read_icfgr0
(
base
);
/* Clear the field, and insert required configuration */
reg_val
&=
~
(
GIC_CFG_MASK
<<
bit_shift
);
reg_val
|=
((
cfg
&
GIC_CFG_MASK
)
<<
bit_shift
);
gicr_write_icfgr0
(
base
,
reg_val
);
}
/*
* Accessor to set the bit fields corresponding to interrupt ID
* in GIC Redistributor ICFGR1.
*/
void
gicr_set_icfgr1
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
cfg
)
{
/* Interrupt configuration is a 2-bit field */
unsigned
int
bit_num
=
id
&
((
1U
<<
ICFGR_SHIFT
)
-
1U
);
unsigned
int
bit_shift
=
bit_num
<<
1U
;
uint32_t
reg_val
=
gicr_read_icfgr1
(
base
);
/* Clear the field, and insert required configuration */
reg_val
&=
~
(
GIC_CFG_MASK
<<
bit_shift
);
reg_val
|=
((
cfg
&
GIC_CFG_MASK
)
<<
bit_shift
);
gicr_write_icfgr1
(
base
,
reg_val
);
}
drivers/arm/gic/v3/gicv3_helpers.c
View file @
6654d17e
...
...
@@ -15,263 +15,6 @@
#include "../common/gic_common_private.h"
#include "gicv3_private.h"
/*
* Accessor to read the GIC Distributor IGRPMODR corresponding to the
* interrupt `id`, 32 interrupt IDs at a time.
*/
unsigned
int
gicd_read_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
n
=
id
>>
IGRPMODR_SHIFT
;
return
mmio_read_32
(
base
+
GICD_IGRPMODR
+
(
n
<<
2
));
}
/*
* Accessor to write the GIC Distributor IGRPMODR corresponding to the
* interrupt `id`, 32 interrupt IDs at a time.
*/
void
gicd_write_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
val
)
{
unsigned
int
n
=
id
>>
IGRPMODR_SHIFT
;
mmio_write_32
(
base
+
GICD_IGRPMODR
+
(
n
<<
2
),
val
);
}
/*
* Accessor to get the bit corresponding to interrupt ID
* in GIC Distributor IGRPMODR.
*/
unsigned
int
gicd_get_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicd_read_igrpmodr
(
base
,
id
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Distributor IGRPMODR.
*/
void
gicd_set_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicd_read_igrpmodr
(
base
,
id
);
gicd_write_igrpmodr
(
base
,
id
,
reg_val
|
(
1U
<<
bit_num
));
}
/*
* Accessor to clear the bit corresponding to interrupt ID
* in GIC Distributor IGRPMODR.
*/
void
gicd_clr_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicd_read_igrpmodr
(
base
,
id
);
gicd_write_igrpmodr
(
base
,
id
,
reg_val
&
~
(
1U
<<
bit_num
));
}
/*
* Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the
* interrupt `id`, 4 interrupts IDs at a time.
*/
unsigned
int
gicr_read_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
n
=
id
>>
IPRIORITYR_SHIFT
;
return
mmio_read_32
(
base
+
GICR_IPRIORITYR
+
(
n
<<
2
));
}
/*
* Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the
* interrupt `id`, 4 interrupts IDs at a time.
*/
void
gicr_write_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
val
)
{
unsigned
int
n
=
id
>>
IPRIORITYR_SHIFT
;
mmio_write_32
(
base
+
GICR_IPRIORITYR
+
(
n
<<
2
),
val
);
}
/*
* Accessor to get the bit corresponding to interrupt ID
* from GIC Re-distributor IGROUPR0.
*/
unsigned
int
gicr_get_igroupr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGROUPR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igroupr0
(
base
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Re-distributor IGROUPR0.
*/
void
gicr_set_igroupr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGROUPR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igroupr0
(
base
);
gicr_write_igroupr0
(
base
,
reg_val
|
(
1U
<<
bit_num
));
}
/*
* Accessor to clear the bit corresponding to interrupt ID
* in GIC Re-distributor IGROUPR0.
*/
void
gicr_clr_igroupr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGROUPR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igroupr0
(
base
);
gicr_write_igroupr0
(
base
,
reg_val
&
~
(
1U
<<
bit_num
));
}
/*
* Accessor to get the bit corresponding to interrupt ID
* from GIC Re-distributor IGRPMODR0.
*/
unsigned
int
gicr_get_igrpmodr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igrpmodr0
(
base
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Re-distributor IGRPMODR0.
*/
void
gicr_set_igrpmodr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igrpmodr0
(
base
);
gicr_write_igrpmodr0
(
base
,
reg_val
|
(
1U
<<
bit_num
));
}
/*
* Accessor to clear the bit corresponding to interrupt ID
* in GIC Re-distributor IGRPMODR0.
*/
void
gicr_clr_igrpmodr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
IGRPMODR_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_igrpmodr0
(
base
);
gicr_write_igrpmodr0
(
base
,
reg_val
&
~
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID
* in GIC Re-distributor ISENABLER0.
*/
void
gicr_set_isenabler0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ISENABLER_SHIFT
)
-
1U
);
gicr_write_isenabler0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
* ICENABLER0.
*/
void
gicr_set_icenabler0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ICENABLER_SHIFT
)
-
1U
);
gicr_write_icenabler0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
* ISACTIVER0.
*/
unsigned
int
gicr_get_isactiver0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ISACTIVER_SHIFT
)
-
1U
);
unsigned
int
reg_val
=
gicr_read_isactiver0
(
base
);
return
(
reg_val
>>
bit_num
)
&
0x1U
;
}
/*
* Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor
* ICPENDRR0.
*/
void
gicr_set_icpendr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ICPENDR_SHIFT
)
-
1U
);
gicr_write_icpendr0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
* ISPENDR0.
*/
void
gicr_set_ispendr0
(
uintptr_t
base
,
unsigned
int
id
)
{
unsigned
int
bit_num
=
id
&
((
1U
<<
ISPENDR_SHIFT
)
-
1U
);
gicr_write_ispendr0
(
base
,
(
1U
<<
bit_num
));
}
/*
* Accessor to set the byte corresponding to interrupt ID
* in GIC Re-distributor IPRIORITYR.
*/
void
gicr_set_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
pri
)
{
uint8_t
val
=
pri
&
GIC_PRI_MASK
;
mmio_write_8
(
base
+
GICR_IPRIORITYR
+
id
,
val
);
}
/*
* Accessor to set the bit fields corresponding to interrupt ID
* in GIC Re-distributor ICFGR0.
*/
void
gicr_set_icfgr0
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
cfg
)
{
/* Interrupt configuration is a 2-bit field */
unsigned
int
bit_num
=
id
&
((
1U
<<
ICFGR_SHIFT
)
-
1U
);
unsigned
int
bit_shift
=
bit_num
<<
1U
;
uint32_t
reg_val
=
gicr_read_icfgr0
(
base
);
/* Clear the field, and insert required configuration */
reg_val
&=
~
(
GIC_CFG_MASK
<<
bit_shift
);
reg_val
|=
((
cfg
&
GIC_CFG_MASK
)
<<
bit_shift
);
gicr_write_icfgr0
(
base
,
reg_val
);
}
/*
* Accessor to set the bit fields corresponding to interrupt ID
* in GIC Re-distributor ICFGR1.
*/
void
gicr_set_icfgr1
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
cfg
)
{
/* Interrupt configuration is a 2-bit field */
unsigned
int
bit_num
=
id
&
((
1U
<<
ICFGR_SHIFT
)
-
1U
);
unsigned
int
bit_shift
=
bit_num
<<
1U
;
uint32_t
reg_val
=
gicr_read_icfgr1
(
base
);
/* Clear the field, and insert required configuration */
reg_val
&=
~
(
GIC_CFG_MASK
<<
bit_shift
);
reg_val
|=
((
cfg
&
GIC_CFG_MASK
)
<<
bit_shift
);
gicr_write_icfgr1
(
base
,
reg_val
);
}
/******************************************************************************
* This function marks the core as awake in the re-distributor and
* ensures that the interface is active.
...
...
@@ -292,7 +35,6 @@ void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base)
;
}
/******************************************************************************
* This function marks the core as asleep in the re-distributor and ensures
* that the interface is quiescent.
...
...
drivers/arm/gic/v3/gicv3_private.h
View file @
6654d17e
/*
* Copyright (c) 2015-20
18
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-20
20
, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -24,6 +24,100 @@
#define RWP_TRUE U(1)
#define RWP_FALSE U(0)
/* Calculate GIC register bit number corresponding to its interrupt ID */
#define BIT_NUM(REG, id) \
((id) & ((1U << REG##_SHIFT) - 1U))
/* Calculate 8-bit GICD register offset corresponding to its interrupt ID */
#define GICD_OFFSET_8(REG, id) \
GICD_##REG + (id)
/* Calculate 32-bit GICD register offset corresponding to its interrupt ID */
#define GICD_OFFSET(REG, id) \
GICD_##REG + (((id) >> REG##_SHIFT) << 2)
/* Calculate 64-bit GICD register offset corresponding to its interrupt ID */
#define GICD_OFFSET_64(REG, id) \
GICD_##REG + (((id) >> REG##_SHIFT) << 3)
/* Read 32-bit GIC Distributor register corresponding to its interrupt ID */
#define GICD_READ(REG, base, id) \
mmio_read_32((base) + GICD_OFFSET(REG, (id)))
/* Read 64-bit GIC Distributor register corresponding to its interrupt ID */
#define GICD_READ_64(REG, base, id) \
mmio_read_64((base) + GICD_OFFSET_64(REG, (id)))
/* Write to 64-bit GIC Distributor register corresponding to its interrupt ID */
#define GICD_WRITE_64(REG, base, id, val) \
mmio_write_64((base) + GICD_OFFSET_64(REG, (id)), (val))
/* Write to 32-bit GIC Distributor register corresponding to its interrupt ID */
#define GICD_WRITE(REG, base, id, val) \
mmio_write_32((base) + GICD_OFFSET(REG, (id)), (val))
/* Write to 8-bit GIC Distributor register corresponding to its interrupt ID */
#define GICD_WRITE_8(REG, base, id, val) \
mmio_write_8((base) + GICD_OFFSET_8(REG, (id)), (val))
/*
* Bit operations on GIC Distributor register corresponding
* to its interrupt ID
*/
/* Get bit in GIC Distributor register */
#define GICD_GET_BIT(REG, base, id) \
((mmio_read_32((base) + GICD_OFFSET(REG, (id))) >> \
BIT_NUM(REG, (id))) & 1U)
/* Set bit in GIC Distributor register */
#define GICD_SET_BIT(REG, base, id) \
mmio_setbits_32((base) + GICD_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/* Clear bit in GIC Distributor register */
#define GICD_CLR_BIT(REG, base, id) \
mmio_clrbits_32((base) + GICD_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/* Write bit in GIC Distributor register */
#define GICD_WRITE_BIT(REG, base, id) \
mmio_write_32((base) + GICD_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/*
* Calculate GICv3 GICR register offset
*/
#define GICR_OFFSET(REG, id) \
GICR_##REG + (((id) >> REG##_SHIFT) << 2)
/* Write to GIC Redistributor register corresponding to its interrupt ID */
#define GICR_WRITE_8(REG, base, id, val) \
mmio_write_8((base) + GICR_##REG + (id), (val))
/*
* Bit operations on GIC Redistributor register
* corresponding to its interrupt ID
*/
/* Get bit in GIC Redistributor register */
#define GICR_GET_BIT(REG, base, id) \
((mmio_read_32((base) + GICR_OFFSET(REG, (id))) >> \
BIT_NUM(REG, (id))) & 1U)
/* Write bit in GIC Redistributor register */
#define GICR_WRITE_BIT(REG, base, id) \
mmio_write_32((base) + GICR_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/* Set bit in GIC Redistributor register */
#define GICR_SET_BIT(REG, base, id) \
mmio_setbits_32((base) + GICR_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/* Clear bit in GIC Redistributor register */
#define GICR_CLR_BIT(REG, base, id) \
mmio_clrbits_32((base) + GICR_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/*
* Macro to convert an mpidr to a value suitable for programming into a
* GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant
...
...
@@ -63,9 +157,9 @@ extern const gicv3_driver_data_t *gicv3_driver_data;
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
******************************************************************************/
u
nsigned
in
t
gicd_read_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
);
u
int32_
t
gicd_read_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
);
unsigned
int
gicr_read_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
);
void
gicd_write_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
,
u
nsigned
in
t
val
);
void
gicd_write_igrpmodr
(
uintptr_t
base
,
unsigned
int
id
,
u
int32_
t
val
);
void
gicr_write_ipriorityr
(
uintptr_t
base
,
unsigned
int
id
,
unsigned
int
val
);
/*******************************************************************************
...
...
@@ -121,27 +215,27 @@ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base);
*/
static
inline
void
gicd_wait_for_pending_write
(
uintptr_t
gicd_base
)
{
while
((
gicd_read_ctlr
(
gicd_base
)
&
GICD_CTLR_RWP_BIT
)
!=
0U
)
;
while
((
gicd_read_ctlr
(
gicd_base
)
&
GICD_CTLR_RWP_BIT
)
!=
0U
)
{
}
}
static
inline
u
nsigned
in
t
gicd_read_pidr2
(
uintptr_t
base
)
static
inline
u
int32_
t
gicd_read_pidr2
(
uintptr_t
base
)
{
return
mmio_read_32
(
base
+
GICD_PIDR2_GICV3
);
}
static
inline
u
nsigned
long
long
gicd_read_irouter
(
uintptr_t
base
,
unsigned
int
id
)
static
inline
u
int64_t
gicd_read_irouter
(
uintptr_t
base
,
unsigned
int
id
)
{
assert
(
id
>=
MIN_SPI_ID
);
return
mmio_read_64
(
base
+
GICD_IROUTER
+
(
id
<<
3
)
);
return
GICD_READ_64
(
IROUTER
,
base
,
id
);
}
static
inline
void
gicd_write_irouter
(
uintptr_t
base
,
unsigned
int
id
,
u
nsigned
long
long
affinity
)
u
int64_t
affinity
)
{
assert
(
id
>=
MIN_SPI_ID
);
mmio_write_64
(
base
+
GICD_IROUTER
+
(
id
<<
3
)
,
affinity
);
GICD_WRITE_64
(
IROUTER
,
base
,
id
,
affinity
);
}
static
inline
void
gicd_clr_ctlr
(
uintptr_t
base
,
...
...
@@ -149,8 +243,9 @@ static inline void gicd_clr_ctlr(uintptr_t base,
unsigned
int
rwp
)
{
gicd_write_ctlr
(
base
,
gicd_read_ctlr
(
base
)
&
~
bitmap
);
if
(
rwp
!=
0U
)
if
(
rwp
!=
0U
)
{
gicd_wait_for_pending_write
(
base
);
}
}
static
inline
void
gicd_set_ctlr
(
uintptr_t
base
,
...
...
@@ -158,8 +253,9 @@ static inline void gicd_set_ctlr(uintptr_t base,
unsigned
int
rwp
)
{
gicd_write_ctlr
(
base
,
gicd_read_ctlr
(
base
)
|
bitmap
);
if
(
rwp
!=
0U
)
if
(
rwp
!=
0U
)
{
gicd_wait_for_pending_write
(
base
);
}
}
/*******************************************************************************
...
...
@@ -175,17 +271,17 @@ static inline void gicr_write_ctlr(uintptr_t base, uint32_t val)
mmio_write_32
(
base
+
GICR_CTLR
,
val
);
}
static
inline
u
nsigned
long
long
gicr_read_typer
(
uintptr_t
base
)
static
inline
u
int64_t
gicr_read_typer
(
uintptr_t
base
)
{
return
mmio_read_64
(
base
+
GICR_TYPER
);
}
static
inline
u
nsigned
in
t
gicr_read_waker
(
uintptr_t
base
)
static
inline
u
int32_
t
gicr_read_waker
(
uintptr_t
base
)
{
return
mmio_read_32
(
base
+
GICR_WAKER
);
}
static
inline
void
gicr_write_waker
(
uintptr_t
base
,
u
nsigned
in
t
val
)
static
inline
void
gicr_write_waker
(
uintptr_t
base
,
u
int32_
t
val
)
{
mmio_write_32
(
base
+
GICR_WAKER
,
val
);
}
...
...
@@ -199,14 +295,14 @@ static inline void gicr_write_waker(uintptr_t base, unsigned int val)
*/
static
inline
void
gicr_wait_for_pending_write
(
uintptr_t
gicr_base
)
{
while
((
gicr_read_ctlr
(
gicr_base
)
&
GICR_CTLR_RWP_BIT
)
!=
0U
)
;
while
((
gicr_read_ctlr
(
gicr_base
)
&
GICR_CTLR_RWP_BIT
)
!=
0U
)
{
}
}
static
inline
void
gicr_wait_for_upstream_pending_write
(
uintptr_t
gicr_base
)
{
while
((
gicr_read_ctlr
(
gicr_base
)
&
GICR_CTLR_UWP_BIT
)
!=
0U
)
;
while
((
gicr_read_ctlr
(
gicr_base
)
&
GICR_CTLR_UWP_BIT
)
!=
0U
)
{
}
}
/* Private implementation of Distributor power control hooks */
...
...
@@ -214,7 +310,7 @@ void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num);
void
arm_gicv3_distif_post_restore
(
unsigned
int
rdist_proc_num
);
/*******************************************************************************
* GIC Re
-
distributor functions for accessing entire registers.
* GIC Redistributor functions for accessing entire registers.
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
******************************************************************************/
...
...
@@ -341,7 +437,7 @@ static inline uint32_t gits_read_ctlr(uintptr_t base)
return
mmio_read_32
(
base
+
GITS_CTLR
);
}
static
inline
void
gits_write_ctlr
(
uintptr_t
base
,
u
nsigned
in
t
val
)
static
inline
void
gits_write_ctlr
(
uintptr_t
base
,
u
int32_
t
val
)
{
mmio_write_32
(
base
+
GITS_CTLR
,
val
);
}
...
...
@@ -366,13 +462,15 @@ static inline void gits_write_cwriter(uintptr_t base, uint64_t val)
mmio_write_64
(
base
+
GITS_CWRITER
,
val
);
}
static
inline
uint64_t
gits_read_baser
(
uintptr_t
base
,
unsigned
int
its_table_id
)
static
inline
uint64_t
gits_read_baser
(
uintptr_t
base
,
unsigned
int
its_table_id
)
{
assert
(
its_table_id
<
8U
);
return
mmio_read_64
(
base
+
GITS_BASER
+
(
8U
*
its_table_id
));
}
static
inline
void
gits_write_baser
(
uintptr_t
base
,
unsigned
int
its_table_id
,
uint64_t
val
)
static
inline
void
gits_write_baser
(
uintptr_t
base
,
unsigned
int
its_table_id
,
uint64_t
val
)
{
assert
(
its_table_id
<
8U
);
mmio_write_64
(
base
+
GITS_BASER
+
(
8U
*
its_table_id
),
val
);
...
...
@@ -384,9 +482,8 @@ static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, u
static
inline
void
gits_wait_for_quiescent_bit
(
uintptr_t
gits_base
)
{
assert
((
gits_read_ctlr
(
gits_base
)
&
GITS_CTLR_ENABLED_BIT
)
==
0U
);
while
((
gits_read_ctlr
(
gits_base
)
&
GITS_CTLR_QUIESCENT_BIT
)
==
0U
)
;
while
((
gits_read_ctlr
(
gits_base
)
&
GITS_CTLR_QUIESCENT_BIT
)
==
0U
)
{
}
}
#endif
/* GICV3_PRIVATE_H */
include/drivers/arm/gicv3.h
View file @
6654d17e
/*
* Copyright (c) 2015-20
19
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-20
20
, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -32,7 +32,7 @@
#define GICD_SETSPI_NSR U(0x40)
#define GICD_CLRSPI_NSR U(0x48)
#define GICD_SETSPI_SR U(0x50)
#define GICD_CLRSPI_SR U(0x5
0
)
#define GICD_CLRSPI_SR U(0x5
8
)
#define GICD_IGRPMODR U(0xd00)
/*
* GICD_IROUTER<n> register is at 0x6000 + 8n, where n is the interrupt id and
...
...
@@ -79,7 +79,7 @@
#define NUM_OF_DIST_REGS 30
/*******************************************************************************
* GICv3 Re
-
distributor interface registers & constants
* GICv3 Redistributor interface registers & constants
******************************************************************************/
#define GICR_PCPUBASE_SHIFT 0x11
#define GICR_SGIBASE_OFFSET U(65536)
/* 64 KB */
...
...
plat/arm/board/fvp/platform.mk
View file @
6654d17e
...
...
@@ -56,6 +56,8 @@ $(eval $(call add_define,FVP_INTERCONNECT_DRIVER))
FVP_GICV3_SOURCES
:=
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
plat/common/plat_gicv3.c
\
plat/arm/common/arm_gicv3.c
...
...
plat/arm/board/n1sdp/platform.mk
View file @
6654d17e
#
# Copyright (c) 2018-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2018-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -18,6 +18,8 @@ N1SDP_CPU_SOURCES := lib/cpus/aarch64/neoverse_n1.S
N1SDP_GIC_SOURCES
:=
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/gic600_multichip.c
\
plat/common/plat_gicv3.c
\
plat/arm/common/arm_gicv3.c
\
...
...
plat/arm/css/sgi/sgi-common.mk
View file @
6654d17e
#
# Copyright (c) 2018-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2018-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -25,6 +25,8 @@ PLAT_INCLUDES += -I${CSS_ENT_BASE}/include
ENT_GIC_SOURCES
:=
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
plat/common/plat_gicv3.c
\
plat/arm/common/arm_gicv3.c
\
drivers/arm/gic/v3/gic600.c
...
...
plat/arm/css/sgm/sgm-common.mk
View file @
6654d17e
#
# Copyright (c) 2018-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2018-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -25,6 +25,8 @@ INTERCONNECT_SOURCES := ${CSS_SGM_BASE}/sgm_interconnect.c
SGM_GIC_SOURCES
:=
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
plat/common/plat_gicv3.c
\
plat/arm/common/arm_gicv3.c
\
drivers/arm/gic/v3/gic600.c
\
...
...
plat/imx/imx8m/imx8mm/platform.mk
View file @
6654d17e
#
# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2019
-2020
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -9,6 +9,8 @@ PLAT_INCLUDES := -Iplat/imx/common/include \
-Iplat
/imx/imx8m/imx8mm/include
IMX_GIC_SOURCES
:=
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/arm_gicv3_common.c
\
drivers/arm/gic/v3/gic500.c
\
drivers/arm/gic/v3/gicv3_main.c
\
...
...
plat/imx/imx8m/imx8mq/platform.mk
View file @
6654d17e
#
# Copyright (c) 2018-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2018-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -9,6 +9,8 @@ PLAT_INCLUDES := -Iplat/imx/common/include \
-Iplat
/imx/imx8m/imx8mq/include
IMX_GIC_SOURCES
:=
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/arm_gicv3_common.c
\
drivers/arm/gic/v3/gic500.c
\
drivers/arm/gic/v3/gicv3_main.c
\
...
...
plat/imx/imx8qm/platform.mk
View file @
6654d17e
#
# Copyright (c) 2015-20
18
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2015-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -8,6 +8,8 @@ PLAT_INCLUDES := -Iplat/imx/imx8qm/include \
-Iplat
/imx/common/include
\
IMX_GIC_SOURCES
:=
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/arm_gicv3_common.c
\
drivers/arm/gic/v3/gic500.c
\
drivers/arm/gic/v3/gicv3_main.c
\
...
...
plat/imx/imx8qx/platform.mk
View file @
6654d17e
#
# Copyright (c) 2015-20
18
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2015-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -8,6 +8,8 @@ PLAT_INCLUDES := -Iplat/imx/imx8qx/include \
-Iplat
/imx/common/include
\
IMX_GIC_SOURCES
:=
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/arm_gicv3_common.c
\
drivers/arm/gic/v3/gic500.c
\
drivers/arm/gic/v3/gicv3_main.c
\
...
...
plat/marvell/a3700/common/a3700_common.mk
View file @
6654d17e
...
...
@@ -81,6 +81,8 @@ $(eval $(call add_define,USE_CCI))
MARVELL_GIC_SOURCES
:=
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/arm_gicv3_common.c
\
plat/common/plat_gicv3.c
\
drivers/arm/gic/v3/gic500.c
...
...
plat/mediatek/mt8183/platform.mk
View file @
6654d17e
...
...
@@ -31,6 +31,8 @@ BL31_SOURCES += common/desc_image_load.c \
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/arm_gicv3_common.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/gic500.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/delay_timer/delay_timer.c
\
...
...
plat/qemu/qemu/platform.mk
View file @
6654d17e
#
# Copyright (c) 2013-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2013-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -140,6 +140,8 @@ QEMU_GICV2_SOURCES := drivers/arm/gic/v2/gicv2_helpers.c \
${PLAT_QEMU_COMMON_PATH}
/qemu_gicv2.c
QEMU_GICV3_SOURCES
:=
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/common/gic_common.c
\
plat/common/plat_gicv3.c
\
...
...
plat/qemu/qemu_sbsa/platform.mk
View file @
6654d17e
...
...
@@ -63,6 +63,8 @@ BL2_SOURCES += ${PLAT_QEMU_COMMON_PATH}/qemu_bl2_mem_params_desc.c \
endif
QEMU_GIC_SOURCES
:=
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/common/gic_common.c
\
plat/common/plat_gicv3.c
\
...
...
plat/rockchip/rk3399/platform.mk
View file @
6654d17e
#
# Copyright (c) 2016-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2016-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -29,6 +29,8 @@ RK_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v3/gic500.c
\
drivers/arm/gic/v3/gicv3_main.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
plat/common/plat_gicv3.c
\
${RK_PLAT}
/common/rockchip_gicv3.c
...
...
plat/socionext/synquacer/platform.mk
View file @
6654d17e
#
# Copyright (c) 2018-20
19
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2018-20
20
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -33,6 +33,8 @@ PLAT_BL_COMMON_SOURCES += $(PLAT_PATH)/sq_helpers.S \
BL31_SOURCES
+=
drivers/arm/ccn/ccn.c
\
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/gicv3_main.c
\
lib/cpus/aarch64/cortex_a53.S
\
plat/common/plat_gicv3.c
\
...
...
plat/socionext/uniphier/platform.mk
View file @
6654d17e
...
...
@@ -58,6 +58,8 @@ BL2_SOURCES += common/desc_image_load.c \
BL31_SOURCES
+=
drivers/arm/cci/cci.c
\
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v3/gicv3_helpers.c
\
drivers/arm/gic/v3/gicdv3_helpers.c
\
drivers/arm/gic/v3/gicrv3_helpers.c
\
drivers/arm/gic/v3/gicv3_main.c
\
lib/cpus/aarch64/cortex_a53.S
\
lib/cpus/aarch64/cortex_a72.S
\
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment