common: Drop linux/delay.h from common header
[oweals/u-boot.git] / board / CZ.NIC / turris_mox / mox_sp.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
4  */
5
6 #include <common.h>
7 #include <asm/arch/soc.h>
8 #include <asm/io.h>
9 #include <linux/delay.h>
10
11 #define RWTM_BASE               (MVEBU_REGISTER(0xb0000))
12 #define RWTM_CMD_PARAM(i)       (size_t)(RWTM_BASE + (i) * 4)
13 #define RWTM_CMD                (RWTM_BASE + 0x40)
14 #define RWTM_CMD_RETSTATUS      (RWTM_BASE + 0x80)
15 #define RWTM_CMD_STATUS(i)      (size_t)(RWTM_BASE + 0x84 + (i) * 4)
16
17 #define RWTM_HOST_INT_RESET     (RWTM_BASE + 0xc8)
18 #define RWTM_HOST_INT_MASK      (RWTM_BASE + 0xcc)
19 #define SP_CMD_COMPLETE         BIT(0)
20
21 #define MBOX_STS_SUCCESS                (0x0 << 30)
22 #define MBOX_STS_FAIL                   (0x1 << 30)
23 #define MBOX_STS_BADCMD                 (0x2 << 30)
24 #define MBOX_STS_LATER                  (0x3 << 30)
25 #define MBOX_STS_ERROR(s)               ((s) & (3 << 30))
26 #define MBOX_STS_VALUE(s)               (((s) >> 10) & 0xfffff)
27 #define MBOX_STS_CMD(s)                 ((s) & 0x3ff)
28
29 enum mbox_cmd {
30         MBOX_CMD_GET_RANDOM     = 1,
31         MBOX_CMD_BOARD_INFO,
32         MBOX_CMD_ECDSA_PUB_KEY,
33         MBOX_CMD_HASH,
34         MBOX_CMD_SIGN,
35         MBOX_CMD_VERIFY,
36
37         MBOX_CMD_OTP_READ,
38         MBOX_CMD_OTP_WRITE
39 };
40
41 static int mbox_do_cmd(enum mbox_cmd cmd, u32 *out, int nout)
42 {
43         const int tries = 50;
44         int i;
45         u32 status;
46
47         clrbits_le32(RWTM_HOST_INT_MASK, SP_CMD_COMPLETE);
48
49         writel(cmd, RWTM_CMD);
50
51         for (i = 0; i < tries; ++i) {
52                 mdelay(10);
53                 if (readl(RWTM_HOST_INT_RESET) & SP_CMD_COMPLETE)
54                         break;
55         }
56
57         if (i == tries) {
58                 /* if timed out, don't read status */
59                 setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
60                 return -ETIMEDOUT;
61         }
62
63         for (i = 0; i < nout; ++i)
64                 out[i] = readl(RWTM_CMD_STATUS(i));
65         status = readl(RWTM_CMD_RETSTATUS);
66
67         setbits_le32(RWTM_HOST_INT_RESET, SP_CMD_COMPLETE);
68
69         if (MBOX_STS_CMD(status) != cmd)
70                 return -EIO;
71         else if (MBOX_STS_ERROR(status) == MBOX_STS_FAIL)
72                 return -(int)MBOX_STS_VALUE(status);
73         else if (MBOX_STS_ERROR(status) != MBOX_STS_SUCCESS)
74                 return -EIO;
75         else
76                 return MBOX_STS_VALUE(status);
77 }
78
79 const char *mox_sp_get_ecdsa_public_key(void)
80 {
81         static char public_key[135];
82         u32 out[16];
83         int res;
84
85         if (public_key[0])
86                 return public_key;
87
88         res = mbox_do_cmd(MBOX_CMD_ECDSA_PUB_KEY, out, 16);
89         if (res < 0)
90                 return NULL;
91
92         sprintf(public_key,
93                 "%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
94                 (u32)res, out[0], out[1], out[2], out[3], out[4], out[5],
95                 out[6], out[7], out[8], out[9], out[10], out[11], out[12],
96                 out[13], out[14], out[15]);
97
98         return public_key;
99 }
100
101 static inline void res_to_mac(u8 *mac, u32 t1, u32 t2)
102 {
103         mac[0] = t1 >> 8;
104         mac[1] = t1;
105         mac[2] = t2 >> 24;
106         mac[3] = t2 >> 16;
107         mac[4] = t2 >> 8;
108         mac[5] = t2;
109 }
110
111 int mbox_sp_get_board_info(u64 *sn, u8 *mac1, u8 *mac2, int *bv, int *ram)
112 {
113         u32 out[8];
114         int res;
115
116         res = mbox_do_cmd(MBOX_CMD_BOARD_INFO, out, 8);
117         if (res < 0)
118                 return res;
119
120         if (sn) {
121                 *sn = out[1];
122                 *sn <<= 32;
123                 *sn |= out[0];
124         }
125
126         if (bv)
127                 *bv = out[2];
128
129         if (ram)
130                 *ram = out[3];
131
132         if (mac1)
133                 res_to_mac(mac1, out[4], out[5]);
134
135         if (mac2)
136                 res_to_mac(mac2, out[6], out[7]);
137
138         return 0;
139 }