1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <crypto/sha_dma.h>
9*54fd6939SJiyong Park #include <lib/mmio.h>
10*54fd6939SJiyong Park #include <plat/common/platform.h>
11*54fd6939SJiyong Park #include <platform_def.h>
12*54fd6939SJiyong Park #include <string.h>
13*54fd6939SJiyong Park
14*54fd6939SJiyong Park #include "aml_private.h"
15*54fd6939SJiyong Park
16*54fd6939SJiyong Park #define SIZE_SHIFT 20
17*54fd6939SJiyong Park #define SIZE_MASK 0x1FF
18*54fd6939SJiyong Park #define SIZE_FWBLK 0x200UL
19*54fd6939SJiyong Park
20*54fd6939SJiyong Park /*
21*54fd6939SJiyong Park * Note: The Amlogic SCP firmware uses the legacy SCPI protocol.
22*54fd6939SJiyong Park */
23*54fd6939SJiyong Park #define SCPI_CMD_SET_CSS_POWER_STATE 0x04
24*54fd6939SJiyong Park #define SCPI_CMD_SET_SYS_POWER_STATE 0x08
25*54fd6939SJiyong Park
26*54fd6939SJiyong Park #define SCPI_CMD_JTAG_SET_STATE 0xC0
27*54fd6939SJiyong Park #define SCPI_CMD_EFUSE_READ 0xC2
28*54fd6939SJiyong Park #define SCPI_CMD_CHIP_ID 0xC6
29*54fd6939SJiyong Park
30*54fd6939SJiyong Park #define SCPI_CMD_COPY_FW 0xd4
31*54fd6939SJiyong Park #define SCPI_CMD_SET_FW_ADDR 0xd3
32*54fd6939SJiyong Park #define SCPI_CMD_FW_SIZE 0xd2
33*54fd6939SJiyong Park
aml_scpi_cmd(uint32_t command,uint32_t size)34*54fd6939SJiyong Park static inline uint32_t aml_scpi_cmd(uint32_t command, uint32_t size)
35*54fd6939SJiyong Park {
36*54fd6939SJiyong Park return command | (size << SIZE_SHIFT);
37*54fd6939SJiyong Park }
38*54fd6939SJiyong Park
aml_scpi_secure_message_send(uint32_t command,uint32_t size)39*54fd6939SJiyong Park static void aml_scpi_secure_message_send(uint32_t command, uint32_t size)
40*54fd6939SJiyong Park {
41*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(command, size));
42*54fd6939SJiyong Park }
43*54fd6939SJiyong Park
aml_scpi_secure_message_receive(void ** message_out,size_t * size_out)44*54fd6939SJiyong Park static uint32_t aml_scpi_secure_message_receive(void **message_out, size_t *size_out)
45*54fd6939SJiyong Park {
46*54fd6939SJiyong Park uint32_t response = aml_mhu_secure_message_wait();
47*54fd6939SJiyong Park
48*54fd6939SJiyong Park size_t size = (response >> SIZE_SHIFT) & SIZE_MASK;
49*54fd6939SJiyong Park
50*54fd6939SJiyong Park response &= ~(SIZE_MASK << SIZE_SHIFT);
51*54fd6939SJiyong Park
52*54fd6939SJiyong Park if (size_out != NULL)
53*54fd6939SJiyong Park *size_out = size;
54*54fd6939SJiyong Park
55*54fd6939SJiyong Park if (message_out != NULL)
56*54fd6939SJiyong Park *message_out = (void *)AML_MHU_SECURE_SCP_TO_AP_PAYLOAD;
57*54fd6939SJiyong Park
58*54fd6939SJiyong Park return response;
59*54fd6939SJiyong Park }
60*54fd6939SJiyong Park
aml_scpi_set_css_power_state(u_register_t mpidr,uint32_t cpu_state,uint32_t cluster_state,uint32_t css_state)61*54fd6939SJiyong Park void aml_scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state,
62*54fd6939SJiyong Park uint32_t cluster_state, uint32_t css_state)
63*54fd6939SJiyong Park {
64*54fd6939SJiyong Park uint32_t state = (mpidr & 0x0F) | /* CPU ID */
65*54fd6939SJiyong Park ((mpidr & 0xF00) >> 4) | /* Cluster ID */
66*54fd6939SJiyong Park (cpu_state << 8) |
67*54fd6939SJiyong Park (cluster_state << 12) |
68*54fd6939SJiyong Park (css_state << 16);
69*54fd6939SJiyong Park
70*54fd6939SJiyong Park aml_mhu_secure_message_start();
71*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, state);
72*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_SET_CSS_POWER_STATE, 4));
73*54fd6939SJiyong Park aml_mhu_secure_message_wait();
74*54fd6939SJiyong Park aml_mhu_secure_message_end();
75*54fd6939SJiyong Park }
76*54fd6939SJiyong Park
aml_scpi_sys_power_state(uint64_t system_state)77*54fd6939SJiyong Park uint32_t aml_scpi_sys_power_state(uint64_t system_state)
78*54fd6939SJiyong Park {
79*54fd6939SJiyong Park uint32_t *response;
80*54fd6939SJiyong Park size_t size;
81*54fd6939SJiyong Park
82*54fd6939SJiyong Park aml_mhu_secure_message_start();
83*54fd6939SJiyong Park mmio_write_8(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, system_state);
84*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_SET_SYS_POWER_STATE, 1));
85*54fd6939SJiyong Park aml_scpi_secure_message_receive((void *)&response, &size);
86*54fd6939SJiyong Park aml_mhu_secure_message_end();
87*54fd6939SJiyong Park
88*54fd6939SJiyong Park return *response;
89*54fd6939SJiyong Park }
90*54fd6939SJiyong Park
aml_scpi_jtag_set_state(uint32_t state,uint8_t select)91*54fd6939SJiyong Park void aml_scpi_jtag_set_state(uint32_t state, uint8_t select)
92*54fd6939SJiyong Park {
93*54fd6939SJiyong Park assert(state <= AML_JTAG_STATE_OFF);
94*54fd6939SJiyong Park
95*54fd6939SJiyong Park if (select > AML_JTAG_A53_EE) {
96*54fd6939SJiyong Park WARN("BL31: Invalid JTAG select (0x%x).\n", select);
97*54fd6939SJiyong Park return;
98*54fd6939SJiyong Park }
99*54fd6939SJiyong Park
100*54fd6939SJiyong Park aml_mhu_secure_message_start();
101*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD,
102*54fd6939SJiyong Park (state << 8) | (uint32_t)select);
103*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_JTAG_SET_STATE, 4));
104*54fd6939SJiyong Park aml_mhu_secure_message_wait();
105*54fd6939SJiyong Park aml_mhu_secure_message_end();
106*54fd6939SJiyong Park }
107*54fd6939SJiyong Park
aml_scpi_efuse_read(void * dst,uint32_t base,uint32_t size)108*54fd6939SJiyong Park uint32_t aml_scpi_efuse_read(void *dst, uint32_t base, uint32_t size)
109*54fd6939SJiyong Park {
110*54fd6939SJiyong Park uint32_t *response;
111*54fd6939SJiyong Park size_t resp_size;
112*54fd6939SJiyong Park
113*54fd6939SJiyong Park if (size > 0x1FC)
114*54fd6939SJiyong Park return 0;
115*54fd6939SJiyong Park
116*54fd6939SJiyong Park aml_mhu_secure_message_start();
117*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, base);
118*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 4, size);
119*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_EFUSE_READ, 8));
120*54fd6939SJiyong Park aml_scpi_secure_message_receive((void *)&response, &resp_size);
121*54fd6939SJiyong Park aml_mhu_secure_message_end();
122*54fd6939SJiyong Park
123*54fd6939SJiyong Park /*
124*54fd6939SJiyong Park * response[0] is the size of the response message.
125*54fd6939SJiyong Park * response[1 ... N] are the contents.
126*54fd6939SJiyong Park */
127*54fd6939SJiyong Park if (*response != 0)
128*54fd6939SJiyong Park memcpy(dst, response + 1, *response);
129*54fd6939SJiyong Park
130*54fd6939SJiyong Park return *response;
131*54fd6939SJiyong Park }
132*54fd6939SJiyong Park
aml_scpi_unknown_thermal(uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)133*54fd6939SJiyong Park void aml_scpi_unknown_thermal(uint32_t arg0, uint32_t arg1,
134*54fd6939SJiyong Park uint32_t arg2, uint32_t arg3)
135*54fd6939SJiyong Park {
136*54fd6939SJiyong Park aml_mhu_secure_message_start();
137*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x0, arg0);
138*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x4, arg1);
139*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x8, arg2);
140*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0xC, arg3);
141*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(0xC3, 16));
142*54fd6939SJiyong Park aml_mhu_secure_message_wait();
143*54fd6939SJiyong Park aml_mhu_secure_message_end();
144*54fd6939SJiyong Park }
145*54fd6939SJiyong Park
aml_scpi_get_chip_id(uint8_t * obuff,uint32_t osize)146*54fd6939SJiyong Park uint32_t aml_scpi_get_chip_id(uint8_t *obuff, uint32_t osize)
147*54fd6939SJiyong Park {
148*54fd6939SJiyong Park uint32_t *response;
149*54fd6939SJiyong Park size_t resp_size;
150*54fd6939SJiyong Park
151*54fd6939SJiyong Park if ((osize != 16) && (osize != 12))
152*54fd6939SJiyong Park return 0;
153*54fd6939SJiyong Park
154*54fd6939SJiyong Park aml_mhu_secure_message_start();
155*54fd6939SJiyong Park aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_CHIP_ID, osize));
156*54fd6939SJiyong Park aml_scpi_secure_message_receive((void *)&response, &resp_size);
157*54fd6939SJiyong Park aml_mhu_secure_message_end();
158*54fd6939SJiyong Park
159*54fd6939SJiyong Park if (!((resp_size == 16) && (osize == 16)) &&
160*54fd6939SJiyong Park !((resp_size == 0) && (osize == 12)))
161*54fd6939SJiyong Park return 0;
162*54fd6939SJiyong Park
163*54fd6939SJiyong Park memcpy((void *)obuff, (const void *)response, osize);
164*54fd6939SJiyong Park
165*54fd6939SJiyong Park return osize;
166*54fd6939SJiyong Park }
167*54fd6939SJiyong Park
aml_scpi_copy_scp_data(uint8_t * data,size_t len)168*54fd6939SJiyong Park static inline void aml_scpi_copy_scp_data(uint8_t *data, size_t len)
169*54fd6939SJiyong Park {
170*54fd6939SJiyong Park void *dst = (void *)AML_MHU_SECURE_AP_TO_SCP_PAYLOAD;
171*54fd6939SJiyong Park size_t sz;
172*54fd6939SJiyong Park
173*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, len);
174*54fd6939SJiyong Park aml_scpi_secure_message_send(SCPI_CMD_FW_SIZE, len);
175*54fd6939SJiyong Park aml_mhu_secure_message_wait();
176*54fd6939SJiyong Park
177*54fd6939SJiyong Park for (sz = 0; sz < len; sz += SIZE_FWBLK) {
178*54fd6939SJiyong Park memcpy(dst, data + sz, MIN(SIZE_FWBLK, len - sz));
179*54fd6939SJiyong Park aml_mhu_secure_message_send(SCPI_CMD_COPY_FW);
180*54fd6939SJiyong Park }
181*54fd6939SJiyong Park }
182*54fd6939SJiyong Park
aml_scpi_set_scp_addr(uint64_t addr,size_t len)183*54fd6939SJiyong Park static inline void aml_scpi_set_scp_addr(uint64_t addr, size_t len)
184*54fd6939SJiyong Park {
185*54fd6939SJiyong Park volatile uint64_t *dst = (uint64_t *)AML_MHU_SECURE_AP_TO_SCP_PAYLOAD;
186*54fd6939SJiyong Park
187*54fd6939SJiyong Park /*
188*54fd6939SJiyong Park * It is ok as AML_MHU_SECURE_AP_TO_SCP_PAYLOAD is mapped as
189*54fd6939SJiyong Park * non cachable
190*54fd6939SJiyong Park */
191*54fd6939SJiyong Park *dst = addr;
192*54fd6939SJiyong Park aml_scpi_secure_message_send(SCPI_CMD_SET_FW_ADDR, sizeof(addr));
193*54fd6939SJiyong Park aml_mhu_secure_message_wait();
194*54fd6939SJiyong Park
195*54fd6939SJiyong Park mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, len);
196*54fd6939SJiyong Park aml_scpi_secure_message_send(SCPI_CMD_FW_SIZE, len);
197*54fd6939SJiyong Park aml_mhu_secure_message_wait();
198*54fd6939SJiyong Park }
199*54fd6939SJiyong Park
aml_scpi_send_fw_hash(uint8_t hash[],size_t len)200*54fd6939SJiyong Park static inline void aml_scpi_send_fw_hash(uint8_t hash[], size_t len)
201*54fd6939SJiyong Park {
202*54fd6939SJiyong Park void *dst = (void *)AML_MHU_SECURE_AP_TO_SCP_PAYLOAD;
203*54fd6939SJiyong Park
204*54fd6939SJiyong Park memcpy(dst, hash, len);
205*54fd6939SJiyong Park aml_mhu_secure_message_send(0xd0);
206*54fd6939SJiyong Park aml_mhu_secure_message_send(0xd1);
207*54fd6939SJiyong Park aml_mhu_secure_message_send(0xd5);
208*54fd6939SJiyong Park aml_mhu_secure_message_end();
209*54fd6939SJiyong Park }
210*54fd6939SJiyong Park
211*54fd6939SJiyong Park /**
212*54fd6939SJiyong Park * Upload a FW to SCP.
213*54fd6939SJiyong Park *
214*54fd6939SJiyong Park * @param addr: firmware data address
215*54fd6939SJiyong Park * @param size: size of firmware
216*54fd6939SJiyong Park * @param send: If set, actually copy the firmware in SCP memory otherwise only
217*54fd6939SJiyong Park * send the firmware address.
218*54fd6939SJiyong Park */
aml_scpi_upload_scp_fw(uintptr_t addr,size_t size,int send)219*54fd6939SJiyong Park void aml_scpi_upload_scp_fw(uintptr_t addr, size_t size, int send)
220*54fd6939SJiyong Park {
221*54fd6939SJiyong Park struct asd_ctx ctx;
222*54fd6939SJiyong Park
223*54fd6939SJiyong Park asd_sha_init(&ctx, ASM_SHA256);
224*54fd6939SJiyong Park asd_sha_update(&ctx, (void *)addr, size);
225*54fd6939SJiyong Park asd_sha_finalize(&ctx);
226*54fd6939SJiyong Park
227*54fd6939SJiyong Park aml_mhu_secure_message_start();
228*54fd6939SJiyong Park if (send == 0)
229*54fd6939SJiyong Park aml_scpi_set_scp_addr(addr, size);
230*54fd6939SJiyong Park else
231*54fd6939SJiyong Park aml_scpi_copy_scp_data((void *)addr, size);
232*54fd6939SJiyong Park
233*54fd6939SJiyong Park aml_scpi_send_fw_hash(ctx.digest, sizeof(ctx.digest));
234*54fd6939SJiyong Park }
235