1 /**
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * Description: Provides tcxo trim port \n
16 *
17 * History: \n
18 * 2024-01-31, Create file. \n
19 */
20 #include "xo_trim_porting.h"
21 #include "efuse.h"
22 #include "efuse_porting.h"
23 #include "clock_init.h"
24 #include "chip_io.h"
25 #include "soc_osal.h"
26 #ifdef CONFIG_MIDDLEWARE_SUPPORT_NV
27 #include "nv.h"
28 #include "tsensor.h"
29 #endif
30
cmu_xo_trim_reg_set(uint32_t fine,uint32_t coarse)31 static void cmu_xo_trim_reg_set(uint32_t fine, uint32_t coarse)
32 {
33 u_cmu_xo_sig val;
34
35 val.u32 = readl(CMU_XO_SIG);
36 val.bits.rg_cmu_xo_trim_coarse = coarse;
37 val.bits.rg_cmu_xo_trim_fine = fine;
38 val.bits.rg_cmu_xo_trim_coarse_sel = XO_TRIM_ENABLE;
39 val.bits.rg_cmu_xo_trim_fine_sel = XO_TRIM_ENABLE;
40 writel(CMU_XO_SIG, val.u32);
41 }
42
cmu_xo_trim_init(void)43 void cmu_xo_trim_init(void)
44 {
45 uint8_t lock = 0;
46 uint16_t value = 0;
47 int index;
48 uint8_t writable = false;
49 uint32_t fine = 0;
50 uint32_t coarse = 0;
51 uint32_t id[EFUSE_GROUP_MAX] = {EXT_EFUSE_XO_TRIM_1_ID, EXT_EFUSE_XO_TRIM_2_ID, EXT_EFUSE_XO_TRIM_3_ID};
52 uint32_t lock_id[EFUSE_GROUP_MAX] = {
53 EXT_EFUSE_RSSI_BAND3_1_ID, EXT_EFUSE_RSSI_BAND3_2_ID, EXT_EFUSE_RSSI_BAND3_3_ID
54 };
55
56 for (index = (EFUSE_GROUP_MAX - 1); index >= 0; --index) {
57 if (uapi_efuse_read_bit(&lock, lock_id[index], EXT_EFUSE_LOCK_XO_TRIM_BIT_POS) != SUCC) {
58 return;
59 }
60 writable = (lock == 0) ? false : true;
61 if (writable == false) {
62 continue;
63 }
64 if (uapi_efuse_read_buffer((uint8_t *)&value, id[index], sizeof(value)) != SUCC) {
65 return;
66 }
67 break;
68 }
69 if (writable == false) {
70 return;
71 }
72 value = (value & 0xFFF);
73 fine = (value & 0xFF);
74 coarse = ((value >> SIZE_8_BITS) & 0xF);
75 cmu_xo_trim_reg_set(fine, coarse);
76 return;
77 }
78 #if defined(CONFIG_MIDDLEWARE_SUPPORT_NV)
79 #define CMU_XO_TRIM_TEMP_PARAM_NUM 8 // 8个温度档位值(fine值)(~-20,0,20,40,60,80,100,100~)
80 #define CMU_XO_TRIM_TEMP_TIMER_LEN 2000 // 2000ms
81 #define CMU_XO_TRIM_TEMP_LOW (-40) // 频偏粗调温补使用温度范围的最低温 用于档位计算
82 #define CMU_XO_TRIM_TEMP_GAP (20) // 温度档位的间隔20度
83 #define CMU_XO_TRIM_TEMP_CODE (3) // 温度档位默认值 对应20~40度
84 #define CMU_XO_TRIM_FINE_CODE_MAX (127) // 最大可调的fine code值
85 osal_timer g_xo_trim_temp_timer;
86 int8_t g_nv_xo_trim_temp_fine_code[CMU_XO_TRIM_TEMP_PARAM_NUM] = {0};
cmu_xo_trim_temp_comp_timer_proc(uint32_t para)87 static void cmu_xo_trim_temp_comp_timer_proc(uint32_t para)
88 {
89 int32_t ret = SUCC;
90 static uint8_t last_temp_code = 255;
91 int8_t cur_temp = 25; // 常温
92 uint8_t temp_code = CMU_XO_TRIM_TEMP_CODE;
93 if (uapi_tsensor_get_current_temp(&cur_temp) == SUCC) {
94 if (cur_temp < CMU_XO_TRIM_TEMP_LOW) {
95 cur_temp = CMU_XO_TRIM_TEMP_LOW;
96 }
97 temp_code = (uint8_t)((cur_temp - CMU_XO_TRIM_TEMP_LOW) / CMU_XO_TRIM_TEMP_GAP);
98 if (temp_code >= CMU_XO_TRIM_TEMP_PARAM_NUM) {
99 temp_code = CMU_XO_TRIM_TEMP_PARAM_NUM - 1;
100 }
101 // 确保上一次的温度码有效 并且当前温度码与上一次不同 执行fine code的刷新
102 if (last_temp_code != temp_code) {
103 u_cmu_xo_sig val;
104 val.u32 = para;
105 int32_t new_fine = (int32_t)val.bits.rg_cmu_xo_trim_fine + g_nv_xo_trim_temp_fine_code[temp_code];
106 new_fine = (new_fine < 0) ? 0 : (new_fine > CMU_XO_TRIM_FINE_CODE_MAX) ?
107 CMU_XO_TRIM_FINE_CODE_MAX : new_fine;
108 val.bits.rg_cmu_xo_trim_fine = (uint32_t)new_fine; // 取值范围0-127
109 writel(CMU_XO_SIG, val.u32);
110 last_temp_code = temp_code;
111 #ifdef SW_UART_DEBUG
112 osal_printk("xo update temp:%u,diff:%d,xo:0x%x\r\n",
113 temp_code, g_nv_xo_trim_temp_fine_code[temp_code], val.u32);
114 #endif
115 }
116 }
117 ret = osal_timer_mod(&g_xo_trim_temp_timer, CMU_XO_TRIM_TEMP_TIMER_LEN);
118 if (ret != SUCC) {
119 osal_printk("xo_trim_temp_comp timer mod err ret:%u!\r\n", ret);
120 }
121 }
cmu_xo_trim_temp_comp_init(void)122 void cmu_xo_trim_temp_comp_init(void)
123 {
124 uint32_t ret;
125 uint8_t sw = 0;
126 uint16_t nv_param_len = 0;
127 if (uapi_nv_read(NV_ID_SYSTEM_XO_TRIM_TEMP_SW, 1, &nv_param_len, &sw) != SUCC) {
128 osal_printk("xo_trim_temp_comp::nv read sw fail!\r\n");
129 return;
130 }
131 // 开关开启的情况下 启动定时器 查询温度 执行温补
132 if (sw == 0) {
133 return;
134 }
135 if (uapi_nv_read(NV_ID_SYSTEM_XO_TRIM_TEMP_PARAM, CMU_XO_TRIM_TEMP_PARAM_NUM, &nv_param_len,
136 (uint8_t *)g_nv_xo_trim_temp_fine_code) != SUCC) {
137 osal_printk("xo_trim_temp_comp::nv read param fail!\r\n");
138 return;
139 }
140 #ifdef SW_UART_DEBUG
141 osal_printk("xo_trim_temp_comp val:%d %d\r\n", g_nv_xo_trim_temp_fine_code[0],
142 g_nv_xo_trim_temp_fine_code[CMU_XO_TRIM_TEMP_PARAM_NUM - 1]);
143 #endif
144 g_xo_trim_temp_timer.timer = NULL; /* 初始化需要置空 */
145 g_xo_trim_temp_timer.handler = (void *)cmu_xo_trim_temp_comp_timer_proc;
146 g_xo_trim_temp_timer.data = readl(CMU_XO_SIG); // 默认的频偏值
147 g_xo_trim_temp_timer.interval = (CMU_XO_TRIM_TEMP_TIMER_LEN << 1); // 首次触发4s 后续2s间隔查询
148 ret = (uint32_t)osal_timer_init(&g_xo_trim_temp_timer);
149 ret |= (uint32_t)osal_timer_start(&g_xo_trim_temp_timer);
150 if (ret != SUCC) {
151 osal_printk("xo_trim_temp_comp timer err ret:%u!\r\n", ret);
152 }
153 }
cmu_xo_trim_temp_comp_print(void)154 void cmu_xo_trim_temp_comp_print(void)
155 {
156 uint32_t i;
157 uint8_t sw = 0;
158 uint16_t nv_param_len = 0;
159 if (uapi_nv_read(NV_ID_SYSTEM_XO_TRIM_TEMP_SW, 1, &nv_param_len, &sw) != SUCC) {
160 osal_printk("xo_trim_temp_comp::nv read sw fail!\r\n");
161 return;
162 }
163 // 开关开启的情况下 启动定时器 查询温度 执行温补
164 if (sw == 0) {
165 osal_printk("xo_trim_temp_comp::switch off!\r\n");
166 return;
167 }
168 for (i = 0; i < CMU_XO_TRIM_TEMP_PARAM_NUM - 1; i++) {
169 osal_printk("TEMP_COMP_RANGE[%u] : [%d, %d], val : [%d]\r\n", i,
170 CMU_XO_TRIM_TEMP_LOW + i * CMU_XO_TRIM_TEMP_GAP, CMU_XO_TRIM_TEMP_LOW + (i + 1) * CMU_XO_TRIM_TEMP_GAP,
171 g_nv_xo_trim_temp_fine_code[i]);
172 }
173 osal_printk("TEMP_COMP_RANGE[%u] : [%d, ~ ], val : [%d]\r\n", i,
174 CMU_XO_TRIM_TEMP_LOW + i * CMU_XO_TRIM_TEMP_GAP, g_nv_xo_trim_temp_fine_code[i]);
175 }
176 #endif