1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************************/
20 
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include "infoblock.h"
25 #include "mxc_device.h"
26 #include "flc.h"
27 
crc15_highbitinput(uint16_t crc15val,uint8_t * input,int bitlength)28 uint16_t crc15_highbitinput(uint16_t crc15val, uint8_t *input, int bitlength)
29 {
30     uint16_t inputbit;
31     uint16_t feedbackbit;
32     int i;
33 
34     for (i = 0; i < bitlength; i++) {
35         inputbit = (input[i / 8] >> (7 - i % 8)) & 0x01;
36         feedbackbit = ((crc15val & 0x4000) >> 14) & 0x01;
37         crc15val <<= 1;
38         if (inputbit ^ feedbackbit) {
39             crc15val ^= 0x4599;
40         }
41     }
42     // Clean up.
43     // Mask off any high bits we were ignoring in the loop.
44     crc15val &= 0x7FFF;
45 
46     return crc15val;
47 }
48 
infoblock_readraw(uint32_t offset,uint8_t * data)49 int infoblock_readraw(uint32_t offset, uint8_t *data)
50 {
51     int result;
52 
53     if ((result = MXC_FLC_UnlockInfoBlock(MXC_INFO0_MEM_BASE)) != E_NO_ERROR) {
54         return result;
55     }
56     memcpy(data, (uint8_t *)MXC_INFO0_MEM_BASE + offset, INFOBLOCK_LINE_SIZE);
57     if ((result = MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE)) != E_NO_ERROR) {
58         return result;
59     }
60 
61     return E_NO_ERROR;
62 }
63 
infoblock_read(uint32_t offset,uint8_t * data,int length)64 int infoblock_read(uint32_t offset, uint8_t *data, int length)
65 {
66     uint8_t oneinfoblockline[INFOBLOCK_LINE_SIZE];
67     int lengthtocopy;
68     uint16_t crc = 0;
69     uint16_t crcexpected;
70     int i;
71     int result;
72     lineformat_e lineformat;
73 
74     if (length > INFOBLOCK_MAXIMUM_READ_LENGTH) {
75         return E_BAD_PARAM;
76     }
77 
78     if (data == NULL) {
79         return E_BAD_PARAM;
80     }
81 
82     switch (offset) {
83     case INFOBLOCK_USN_OFFSET:
84         lineformat = INFOBLOCK_LINE_FORMAT_USN;
85         break;
86     case INFOBLOCK_ICE_LOCK_OFFSET:
87         lineformat = INFOBLOCK_LINE_FORMAT_RAW;
88         break;
89     case INFOBLOCK_KEY_OFFSET:
90         lineformat = INFOBLOCK_LINE_FORMAT_DESIGN;
91         break;
92     default:
93         lineformat = INFOBLOCK_LINE_FORMAT_RAW;
94         break;
95     }
96 
97     while (length > 0) {
98         if ((result = infoblock_readraw(offset, oneinfoblockline)) != E_NO_ERROR) {
99             return result;
100         }
101 
102         switch (lineformat) {
103         case INFOBLOCK_LINE_FORMAT_USN:
104             // NO CRC15, ignore lowest 15 bits
105             // Lock bit is high bit, bit 63.
106             // Data is middle 48 bits 62 to 15.
107             // CRC15 is lower 15 bits (bits 0-14)
108             // First shift data one bit left starting at the high byte.
109             for (i = 7; i > 1; i--) {
110                 oneinfoblockline[i] <<= 1;
111                 oneinfoblockline[i] |= (oneinfoblockline[i - 1] & 0x80) >> 7;
112             }
113             // Then, shift data by two bytes
114             memmove(oneinfoblockline, oneinfoblockline + INFOBLOCK_LINE_OVERHEAD, 6);
115             lengthtocopy = INFOBLOCK_LINE_SIZE - INFOBLOCK_LINE_OVERHEAD;
116             break;
117         case INFOBLOCK_LINE_FORMAT_RAW:
118             lengthtocopy = INFOBLOCK_LINE_SIZE;
119             break;
120         case INFOBLOCK_LINE_FORMAT_DESIGN:
121             // Check for unprogrammed information block line
122             crc = 0xFF;
123             for (i = 0; i < sizeof(oneinfoblockline); i++) {
124                 crc &= oneinfoblockline[i];
125             }
126             if (crc == 0xFF) {
127                 // Line is unprogrammed, return error.
128                 return E_BAD_STATE;
129             }
130             // Lock bit is high bit, bit 63.
131             // CRC15 is middle 15 bits [62:48]
132             // Data is lower 48 bits [47:0].
133             // First, CRC the lock bit.
134             crc = crc15_highbitinput(0, oneinfoblockline + 7, 1);
135             // Then CRC the data from high to low bits.  (bit 47 to 0)
136             for (i = 5; i >= 0; i--) {
137                 crc = crc15_highbitinput(crc, oneinfoblockline + i, 8);
138             }
139             crcexpected = ((oneinfoblockline[7] & 0x7F) << 8) | oneinfoblockline[6];
140             if (crc != crcexpected) {
141                 return E_BAD_STATE;
142             }
143             lengthtocopy = INFOBLOCK_LINE_SIZE - INFOBLOCK_LINE_OVERHEAD;
144             break;
145         default:
146             // NOTE: Should never get here.
147             return E_BAD_STATE;
148             break;
149         }
150 
151         if (lengthtocopy > length) {
152             lengthtocopy = length;
153         }
154         memcpy(data, oneinfoblockline, lengthtocopy);
155         data += lengthtocopy;
156         length -= lengthtocopy;
157         offset += INFOBLOCK_LINE_SIZE;
158     }
159 
160     return E_NO_ERROR;
161 }
162