2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
9 #include <common/debug.h>
10 #include <drivers/arm/tzc_dmc620.h>
13 /* Mask to extract bit 31 to 16 */
14 #define MASK_31_16 UINT64_C(0x0000ffff0000)
15 /* Mask to extract bit 47 to 32 */
16 #define MASK_47_32 UINT64_C(0xffff00000000)
18 /* Helper macro for getting dmc_base addr of a dmc_inst */
19 #define DMC_BASE(plat_data, dmc_inst) \
20 ((uintptr_t)(plat_data->dmc_base[dmc_inst]))
22 /* Pointer to the tzc_dmc620_config_data structure populated by the platform */
23 static const tzc_dmc620_config_data_t
*g_plat_config_data
;
27 * Helper function to check if the DMC-620 instance is present at the
28 * base address provided by the platform and also check if at least
29 * one dmc instance is present.
31 static void tzc_dmc620_validate_plat_driver_data(
32 const tzc_dmc620_driver_data_t
*plat_driver_data
)
34 uint8_t dmc_inst
, dmc_count
;
38 assert(plat_driver_data
!= NULL
);
40 dmc_count
= plat_driver_data
->dmc_count
;
41 assert(dmc_count
> 0U);
43 for (dmc_inst
= 0U; dmc_inst
< dmc_count
; dmc_inst
++) {
44 base
= DMC_BASE(plat_driver_data
, dmc_inst
);
45 dmc_id
= mmio_read_32(base
+ DMC620_PERIPHERAL_ID_0
);
46 assert(dmc_id
== DMC620_PERIPHERAL_ID_0_VALUE
);
52 * Program a region with region base and region top addresses of all
55 static void tzc_dmc620_configure_region(int region_no
,
56 unsigned long long region_base
,
57 unsigned long long region_top
,
58 unsigned int sec_attr
)
60 uint32_t min_31_00
, min_47_32
;
61 uint32_t max_31_00
, max_47_32
;
62 uint8_t dmc_inst
, dmc_count
;
64 const tzc_dmc620_driver_data_t
*plat_driver_data
;
66 plat_driver_data
= g_plat_config_data
->plat_drv_data
;
67 assert(plat_driver_data
!= NULL
);
69 /* Do range checks on regions. */
70 assert((region_no
>= 0U) && (region_no
<= DMC620_ACC_ADDR_COUNT
));
72 /* region_base and (region_top + 1) must be 4KB aligned */
73 assert(((region_base
| (region_top
+ 1U)) & (4096U - 1U)) == 0U);
75 dmc_count
= plat_driver_data
->dmc_count
;
76 for (dmc_inst
= 0U; dmc_inst
< dmc_count
; dmc_inst
++) {
77 min_31_00
= (region_base
& MASK_31_16
) | sec_attr
;
78 min_47_32
= (region_base
& MASK_47_32
)
79 >> DMC620_ACC_ADDR_WIDTH
;
80 max_31_00
= (region_top
& MASK_31_16
);
81 max_47_32
= (region_top
& MASK_47_32
)
82 >> DMC620_ACC_ADDR_WIDTH
;
84 /* Extract the base address of the DMC-620 instance */
85 base
= DMC_BASE(plat_driver_data
, dmc_inst
);
86 /* Configure access address region registers */
87 mmio_write_32(base
+ DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no
),
89 mmio_write_32(base
+ DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no
),
91 mmio_write_32(base
+ DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no
),
93 mmio_write_32(base
+ DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no
),
99 * Set the action value for all the DMC-620 instances.
101 static void tzc_dmc620_set_action(void)
103 uint8_t dmc_inst
, dmc_count
;
105 const tzc_dmc620_driver_data_t
*plat_driver_data
;
107 plat_driver_data
= g_plat_config_data
->plat_drv_data
;
108 dmc_count
= plat_driver_data
->dmc_count
;
109 for (dmc_inst
= 0U; dmc_inst
< dmc_count
; dmc_inst
++) {
110 /* Extract the base address of the DMC-620 instance */
111 base
= DMC_BASE(plat_driver_data
, dmc_inst
);
112 /* Switch to READY */
113 mmio_write_32(base
+ DMC620_MEMC_CMD
, DMC620_MEMC_CMD_GO
);
114 mmio_write_32(base
+ DMC620_MEMC_CMD
, DMC620_MEMC_CMD_EXECUTE
);
119 * Verify whether the DMC-620 configuration is complete by reading back
120 * configuration registers and comparing it with the configured value. If
121 * configuration is incomplete, loop till the configured value is reflected in
124 static void tzc_dmc620_verify_complete(void)
126 uint8_t dmc_inst
, dmc_count
;
128 const tzc_dmc620_driver_data_t
*plat_driver_data
;
130 plat_driver_data
= g_plat_config_data
->plat_drv_data
;
131 dmc_count
= plat_driver_data
->dmc_count
;
132 for (dmc_inst
= 0U; dmc_inst
< dmc_count
; dmc_inst
++) {
133 /* Extract the base address of the DMC-620 instance */
134 base
= DMC_BASE(plat_driver_data
, dmc_inst
);
135 while ((mmio_read_32(base
+ DMC620_MEMC_STATUS
) &
136 DMC620_MEMC_CMD_MASK
) != DMC620_MEMC_CMD_GO
)
142 * Initialize the DMC-620 TrustZone Controller using the region configuration
143 * supplied by the platform. The DMC620 controller should be enabled elsewhere
144 * before invoking this function.
146 void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t
*plat_config_data
)
150 /* Check if valid pointer is passed */
151 assert(plat_config_data
!= NULL
);
154 * Check if access address count passed by the platform is less than or
155 * equal to DMC620's access address count
157 assert(plat_config_data
->acc_addr_count
<= DMC620_ACC_ADDR_COUNT
);
159 #if ENABLE_ASSERTIONS
160 /* Validates the information passed by platform */
161 tzc_dmc620_validate_plat_driver_data(plat_config_data
->plat_drv_data
);
164 g_plat_config_data
= plat_config_data
;
166 INFO("Configuring DMC-620 TZC settings\n");
167 for (i
= 0U; i
< g_plat_config_data
->acc_addr_count
; i
++)
168 tzc_dmc620_configure_region(i
,
169 g_plat_config_data
->plat_acc_addr_data
[i
].region_base
,
170 g_plat_config_data
->plat_acc_addr_data
[i
].region_top
,
171 g_plat_config_data
->plat_acc_addr_data
[i
].sec_attr
);
173 tzc_dmc620_set_action();
174 tzc_dmc620_verify_complete();
175 INFO("DMC-620 TZC setup completed\n");