carl9170: Update based on commit 467556acea56f361a21b2a3761ca056b9da2d237 dated Nov...
[linux-libre-firmware.git] / carl9170fw / carlfw / src / cam.c
1 /*
2  * carl9170 firmware - used by the ar9170 wireless device
3  *
4  * Security Engine
5  *
6  * Copyright (c) 2000-2005 ZyDAS Technology Corporation
7  * Copyright (c) 2007-2009 Atheros Communications, Inc.
8  * Copyright    2009    Johannes Berg <johannes@sipsolutions.net>
9  * Copyright 2009-2011  Christian Lamparter <chunkeey@googlemail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "carl9170.h"
26 #include "cam.h"
27
28 #ifdef CONFIG_CARL9170FW_SECURITY_ENGINE
29 static void disable_cam_user(const uint16_t userId)
30 {
31         if (userId <= 31)
32                 andl(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_L, (~((uint32_t) 1 << userId)));
33         else if (userId <= 63)
34                 andl(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_H, (~((uint32_t) 1 << (userId - 32))));
35 }
36
37 static void enable_cam_user(const uint16_t userId)
38 {
39         if (userId <= 31)
40                 orl(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_L, (((uint32_t) 1) << userId));
41         else if (userId <= 63)
42                 orl(AR9170_MAC_REG_CAM_ROLL_CALL_TBL_H, (((uint32_t) 1) << (userId - 32)));
43 }
44
45 static void wait_for_cam_read_ready(void)
46 {
47         while ((get(AR9170_MAC_REG_CAM_STATE) & AR9170_MAC_CAM_STATE_READ_PENDING) == 0) {
48                 /*
49                  * wait
50                  */
51         }
52 }
53
54 static void wait_for_cam_write_ready(void)
55 {
56         while ((get(AR9170_MAC_REG_CAM_STATE) & AR9170_MAC_CAM_STATE_WRITE_PENDING) == 0) {
57                 /*
58                  * wait some more
59                  */
60         }
61 }
62
63 static void HW_CAM_Avail(void)
64 {
65         uint32_t tmpValue;
66
67         do {
68                 tmpValue = get(AR9170_MAC_REG_CAM_MODE);
69         } while (tmpValue & AR9170_MAC_CAM_HOST_PENDING);
70 }
71
72 static void HW_CAM_Write128(const uint32_t address, const uint32_t *data)
73 {
74         HW_CAM_Avail();
75
76         set(AR9170_MAC_REG_CAM_DATA0, data[0]);
77         set(AR9170_MAC_REG_CAM_DATA1, data[1]);
78         set(AR9170_MAC_REG_CAM_DATA2, data[2]);
79         set(AR9170_MAC_REG_CAM_DATA3, data[3]);
80
81         set(AR9170_MAC_REG_CAM_ADDR, address | AR9170_MAC_CAM_ADDR_WRITE);
82
83         wait_for_cam_write_ready();
84 }
85
86 static void HW_CAM_Read128(const uint32_t address, uint32_t *data)
87 {
88
89         HW_CAM_Avail();
90         set(AR9170_MAC_REG_CAM_ADDR, address);
91
92         wait_for_cam_read_ready();
93         HW_CAM_Avail();
94         data[0] = get(AR9170_MAC_REG_CAM_DATA0);
95         data[1] = get(AR9170_MAC_REG_CAM_DATA1);
96         data[2] = get(AR9170_MAC_REG_CAM_DATA2);
97         data[3] = get(AR9170_MAC_REG_CAM_DATA3);
98 }
99
100 void set_key(const struct carl9170_set_key_cmd *key)
101 {
102         uint32_t data[4];
103         uint16_t row, wordId, nibbleId, i;
104
105         if (key->user > (AR9170_CAM_MAX_USER + 3))
106                 return ;
107
108         if (key->keyId > 1)
109                 return ;
110
111         /* Disable Key */
112         disable_cam_user(key->user);
113
114         /* Set encrypt type */
115         if (key->user >= AR9170_CAM_MAX_USER) {
116                 /* default */
117                 row = DEFAULT_ENCRY_TYPE;
118                 wordId = 0;
119                 nibbleId = (key->user - AR9170_CAM_MAX_USER) & 0x7;
120         } else {
121                 row = ENCRY_TYPE_START_ADDR + (key->user >> 5);
122                 wordId = (key->user >> 3) & 0x3;
123                 nibbleId = key->user & 0x7;
124         }
125
126         HW_CAM_Read128(row, data);
127         data[wordId] &= (~(0xf << ((uint32_t) nibbleId * 4)));
128         data[wordId] |= (key->type << ((uint32_t) nibbleId * 4));
129         HW_CAM_Write128(row, data);
130
131         /* Set MAC address */
132         if (key->user < AR9170_CAM_MAX_USER) {
133                 uint16_t byteId;
134                 wordId = (key->user >> 2) & 0x3;
135                 byteId = key->user & 0x3;
136                 row = (key->user >> 4) * 6;
137
138                 for (i = 0; i < 6; i++) {
139                         HW_CAM_Read128(row + i, data);
140                         data[wordId] &= (~(0xff << ((uint32_t) byteId * 8)));
141                         data[wordId] |= (key->macAddr[i] << ((uint32_t) byteId * 8));
142                         HW_CAM_Write128(row + i, data);
143                 }
144         }
145
146         /* Set key */
147         row = KEY_START_ADDR + (key->user * 2) + key->keyId;
148
149         HW_CAM_Write128(row, key->key);
150
151         /* Enable Key */
152         enable_cam_user(key->user);
153 }
154
155 void disable_key(const struct carl9170_disable_key_cmd *key)
156 {
157         disable_cam_user(key->user);
158 }
159
160 #endif /* CONFIG_CARL9170FW_SECURITY_ENGINE */