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