18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 78c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 88c2ecf20Sopenharmony_ci#include <linux/clk/at91_pmc.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 118c2ecf20Sopenharmony_ci#include <linux/regmap.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "pmc.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define PLL_STATUS_MASK(id) (1 << (1 + (id))) 168c2ecf20Sopenharmony_ci#define PLL_REG(id) (AT91_CKGR_PLLAR + ((id) * 4)) 178c2ecf20Sopenharmony_ci#define PLL_DIV_MASK 0xff 188c2ecf20Sopenharmony_ci#define PLL_DIV_MAX PLL_DIV_MASK 198c2ecf20Sopenharmony_ci#define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) 208c2ecf20Sopenharmony_ci#define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ 218c2ecf20Sopenharmony_ci (layout)->mul_mask) 228c2ecf20Sopenharmony_ci#define PLL_MUL_MIN 2 238c2ecf20Sopenharmony_ci#define PLL_MUL_MASK(layout) ((layout)->mul_mask) 248c2ecf20Sopenharmony_ci#define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1) 258c2ecf20Sopenharmony_ci#define PLL_ICPR_SHIFT(id) ((id) * 16) 268c2ecf20Sopenharmony_ci#define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) 278c2ecf20Sopenharmony_ci#define PLL_MAX_COUNT 0x3f 288c2ecf20Sopenharmony_ci#define PLL_COUNT_SHIFT 8 298c2ecf20Sopenharmony_ci#define PLL_OUT_SHIFT 14 308c2ecf20Sopenharmony_ci#define PLL_MAX_ID 1 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct clk_pll { 358c2ecf20Sopenharmony_ci struct clk_hw hw; 368c2ecf20Sopenharmony_ci struct regmap *regmap; 378c2ecf20Sopenharmony_ci u8 id; 388c2ecf20Sopenharmony_ci u8 div; 398c2ecf20Sopenharmony_ci u8 range; 408c2ecf20Sopenharmony_ci u16 mul; 418c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout; 428c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline bool clk_pll_ready(struct regmap *regmap, int id) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci unsigned int status; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return status & PLL_STATUS_MASK(id) ? 1 : 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int clk_pll_prepare(struct clk_hw *hw) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct clk_pll *pll = to_clk_pll(hw); 578c2ecf20Sopenharmony_ci struct regmap *regmap = pll->regmap; 588c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout = pll->layout; 598c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics = 608c2ecf20Sopenharmony_ci pll->characteristics; 618c2ecf20Sopenharmony_ci u8 id = pll->id; 628c2ecf20Sopenharmony_ci u32 mask = PLL_STATUS_MASK(id); 638c2ecf20Sopenharmony_ci int offset = PLL_REG(id); 648c2ecf20Sopenharmony_ci u8 out = 0; 658c2ecf20Sopenharmony_ci unsigned int pllr; 668c2ecf20Sopenharmony_ci unsigned int status; 678c2ecf20Sopenharmony_ci u8 div; 688c2ecf20Sopenharmony_ci u16 mul; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci regmap_read(regmap, offset, &pllr); 718c2ecf20Sopenharmony_ci div = PLL_DIV(pllr); 728c2ecf20Sopenharmony_ci mul = PLL_MUL(pllr, layout); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 758c2ecf20Sopenharmony_ci if ((status & mask) && 768c2ecf20Sopenharmony_ci (div == pll->div && mul == pll->mul)) 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (characteristics->out) 808c2ecf20Sopenharmony_ci out = characteristics->out[pll->range]; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (characteristics->icpll) 838c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id), 848c2ecf20Sopenharmony_ci characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id)); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci regmap_update_bits(regmap, offset, layout->pllr_mask, 878c2ecf20Sopenharmony_ci pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | 888c2ecf20Sopenharmony_ci (out << PLL_OUT_SHIFT) | 898c2ecf20Sopenharmony_ci ((pll->mul & layout->mul_mask) << layout->mul_shift)); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci while (!clk_pll_ready(regmap, pll->id)) 928c2ecf20Sopenharmony_ci cpu_relax(); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int clk_pll_is_prepared(struct clk_hw *hw) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct clk_pll *pll = to_clk_pll(hw); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return clk_pll_ready(pll->regmap, pll->id); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void clk_pll_unprepare(struct clk_hw *hw) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct clk_pll *pll = to_clk_pll(hw); 1078c2ecf20Sopenharmony_ci unsigned int mask = pll->layout->pllr_mask; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic unsigned long clk_pll_recalc_rate(struct clk_hw *hw, 1138c2ecf20Sopenharmony_ci unsigned long parent_rate) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct clk_pll *pll = to_clk_pll(hw); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (!pll->div || !pll->mul) 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return (parent_rate / pll->div) * (pll->mul + 1); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, 1248c2ecf20Sopenharmony_ci unsigned long parent_rate, 1258c2ecf20Sopenharmony_ci u32 *div, u32 *mul, 1268c2ecf20Sopenharmony_ci u32 *index) { 1278c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout = pll->layout; 1288c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics = 1298c2ecf20Sopenharmony_ci pll->characteristics; 1308c2ecf20Sopenharmony_ci unsigned long bestremainder = ULONG_MAX; 1318c2ecf20Sopenharmony_ci unsigned long maxdiv, mindiv, tmpdiv; 1328c2ecf20Sopenharmony_ci long bestrate = -ERANGE; 1338c2ecf20Sopenharmony_ci unsigned long bestdiv; 1348c2ecf20Sopenharmony_ci unsigned long bestmul; 1358c2ecf20Sopenharmony_ci int i = 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Check if parent_rate is a valid input rate */ 1388c2ecf20Sopenharmony_ci if (parent_rate < characteristics->input.min) 1398c2ecf20Sopenharmony_ci return -ERANGE; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* 1428c2ecf20Sopenharmony_ci * Calculate minimum divider based on the minimum multiplier, the 1438c2ecf20Sopenharmony_ci * parent_rate and the requested rate. 1448c2ecf20Sopenharmony_ci * Should always be 2 according to the input and output characteristics 1458c2ecf20Sopenharmony_ci * of the PLL blocks. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci mindiv = (parent_rate * PLL_MUL_MIN) / rate; 1488c2ecf20Sopenharmony_ci if (!mindiv) 1498c2ecf20Sopenharmony_ci mindiv = 1; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (parent_rate > characteristics->input.max) { 1528c2ecf20Sopenharmony_ci tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max); 1538c2ecf20Sopenharmony_ci if (tmpdiv > PLL_DIV_MAX) 1548c2ecf20Sopenharmony_ci return -ERANGE; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (tmpdiv > mindiv) 1578c2ecf20Sopenharmony_ci mindiv = tmpdiv; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * Calculate the maximum divider which is limited by PLL register 1628c2ecf20Sopenharmony_ci * layout (limited by the MUL or DIV field size). 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate); 1658c2ecf20Sopenharmony_ci if (maxdiv > PLL_DIV_MAX) 1668c2ecf20Sopenharmony_ci maxdiv = PLL_DIV_MAX; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Iterate over the acceptable divider values to find the best 1708c2ecf20Sopenharmony_ci * divider/multiplier pair (the one that generates the closest 1718c2ecf20Sopenharmony_ci * rate to the requested one). 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { 1748c2ecf20Sopenharmony_ci unsigned long remainder; 1758c2ecf20Sopenharmony_ci unsigned long tmprate; 1768c2ecf20Sopenharmony_ci unsigned long tmpmul; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* 1798c2ecf20Sopenharmony_ci * Calculate the multiplier associated with the current 1808c2ecf20Sopenharmony_ci * divider that provide the closest rate to the requested one. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv); 1838c2ecf20Sopenharmony_ci tmprate = (parent_rate / tmpdiv) * tmpmul; 1848c2ecf20Sopenharmony_ci if (tmprate > rate) 1858c2ecf20Sopenharmony_ci remainder = tmprate - rate; 1868c2ecf20Sopenharmony_ci else 1878c2ecf20Sopenharmony_ci remainder = rate - tmprate; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * Compare the remainder with the best remainder found until 1918c2ecf20Sopenharmony_ci * now and elect a new best multiplier/divider pair if the 1928c2ecf20Sopenharmony_ci * current remainder is smaller than the best one. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci if (remainder < bestremainder) { 1958c2ecf20Sopenharmony_ci bestremainder = remainder; 1968c2ecf20Sopenharmony_ci bestdiv = tmpdiv; 1978c2ecf20Sopenharmony_ci bestmul = tmpmul; 1988c2ecf20Sopenharmony_ci bestrate = tmprate; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * We've found a perfect match! 2038c2ecf20Sopenharmony_ci * Stop searching now and use this multiplier/divider pair. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci if (!remainder) 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* We haven't found any multiplier/divider pair => return -ERANGE */ 2108c2ecf20Sopenharmony_ci if (bestrate < 0) 2118c2ecf20Sopenharmony_ci return bestrate; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Check if bestrate is a valid output rate */ 2148c2ecf20Sopenharmony_ci for (i = 0; i < characteristics->num_output; i++) { 2158c2ecf20Sopenharmony_ci if (bestrate >= characteristics->output[i].min && 2168c2ecf20Sopenharmony_ci bestrate <= characteristics->output[i].max) 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (i >= characteristics->num_output) 2218c2ecf20Sopenharmony_ci return -ERANGE; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (div) 2248c2ecf20Sopenharmony_ci *div = bestdiv; 2258c2ecf20Sopenharmony_ci if (mul) 2268c2ecf20Sopenharmony_ci *mul = bestmul - 1; 2278c2ecf20Sopenharmony_ci if (index) 2288c2ecf20Sopenharmony_ci *index = i; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return bestrate; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, 2348c2ecf20Sopenharmony_ci unsigned long *parent_rate) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct clk_pll *pll = to_clk_pll(hw); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return clk_pll_get_best_div_mul(pll, rate, *parent_rate, 2398c2ecf20Sopenharmony_ci NULL, NULL, NULL); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 2438c2ecf20Sopenharmony_ci unsigned long parent_rate) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct clk_pll *pll = to_clk_pll(hw); 2468c2ecf20Sopenharmony_ci long ret; 2478c2ecf20Sopenharmony_ci u32 div; 2488c2ecf20Sopenharmony_ci u32 mul; 2498c2ecf20Sopenharmony_ci u32 index; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ret = clk_pll_get_best_div_mul(pll, rate, parent_rate, 2528c2ecf20Sopenharmony_ci &div, &mul, &index); 2538c2ecf20Sopenharmony_ci if (ret < 0) 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci pll->range = index; 2578c2ecf20Sopenharmony_ci pll->div = div; 2588c2ecf20Sopenharmony_ci pll->mul = mul; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic const struct clk_ops pll_ops = { 2648c2ecf20Sopenharmony_ci .prepare = clk_pll_prepare, 2658c2ecf20Sopenharmony_ci .unprepare = clk_pll_unprepare, 2668c2ecf20Sopenharmony_ci .is_prepared = clk_pll_is_prepared, 2678c2ecf20Sopenharmony_ci .recalc_rate = clk_pll_recalc_rate, 2688c2ecf20Sopenharmony_ci .round_rate = clk_pll_round_rate, 2698c2ecf20Sopenharmony_ci .set_rate = clk_pll_set_rate, 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistruct clk_hw * __init 2738c2ecf20Sopenharmony_ciat91_clk_register_pll(struct regmap *regmap, const char *name, 2748c2ecf20Sopenharmony_ci const char *parent_name, u8 id, 2758c2ecf20Sopenharmony_ci const struct clk_pll_layout *layout, 2768c2ecf20Sopenharmony_ci const struct clk_pll_characteristics *characteristics) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct clk_pll *pll; 2798c2ecf20Sopenharmony_ci struct clk_hw *hw; 2808c2ecf20Sopenharmony_ci struct clk_init_data init; 2818c2ecf20Sopenharmony_ci int offset = PLL_REG(id); 2828c2ecf20Sopenharmony_ci unsigned int pllr; 2838c2ecf20Sopenharmony_ci int ret; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (id > PLL_MAX_ID) 2868c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 2898c2ecf20Sopenharmony_ci if (!pll) 2908c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci init.name = name; 2938c2ecf20Sopenharmony_ci init.ops = &pll_ops; 2948c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 2958c2ecf20Sopenharmony_ci init.num_parents = 1; 2968c2ecf20Sopenharmony_ci init.flags = CLK_SET_RATE_GATE; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci pll->id = id; 2998c2ecf20Sopenharmony_ci pll->hw.init = &init; 3008c2ecf20Sopenharmony_ci pll->layout = layout; 3018c2ecf20Sopenharmony_ci pll->characteristics = characteristics; 3028c2ecf20Sopenharmony_ci pll->regmap = regmap; 3038c2ecf20Sopenharmony_ci regmap_read(regmap, offset, &pllr); 3048c2ecf20Sopenharmony_ci pll->div = PLL_DIV(pllr); 3058c2ecf20Sopenharmony_ci pll->mul = PLL_MUL(pllr, layout); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci hw = &pll->hw; 3088c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, &pll->hw); 3098c2ecf20Sopenharmony_ci if (ret) { 3108c2ecf20Sopenharmony_ci kfree(pll); 3118c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return hw; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ciconst struct clk_pll_layout at91rm9200_pll_layout = { 3198c2ecf20Sopenharmony_ci .pllr_mask = 0x7FFFFFF, 3208c2ecf20Sopenharmony_ci .mul_shift = 16, 3218c2ecf20Sopenharmony_ci .mul_mask = 0x7FF, 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ciconst struct clk_pll_layout at91sam9g45_pll_layout = { 3258c2ecf20Sopenharmony_ci .pllr_mask = 0xFFFFFF, 3268c2ecf20Sopenharmony_ci .mul_shift = 16, 3278c2ecf20Sopenharmony_ci .mul_mask = 0xFF, 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ciconst struct clk_pll_layout at91sam9g20_pllb_layout = { 3318c2ecf20Sopenharmony_ci .pllr_mask = 0x3FFFFF, 3328c2ecf20Sopenharmony_ci .mul_shift = 16, 3338c2ecf20Sopenharmony_ci .mul_mask = 0x3F, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ciconst struct clk_pll_layout sama5d3_pll_layout = { 3378c2ecf20Sopenharmony_ci .pllr_mask = 0x1FFFFFF, 3388c2ecf20Sopenharmony_ci .mul_shift = 18, 3398c2ecf20Sopenharmony_ci .mul_mask = 0x7F, 3408c2ecf20Sopenharmony_ci}; 341