162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/kyro/STG4000InitDevice.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2000 Imagination Technologies Ltd 562306a36Sopenharmony_ci * Copyright (C) 2002 STMicroelectronics 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 862306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 962306a36Sopenharmony_ci * for more details. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/pci.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "STG4000Reg.h" 1862306a36Sopenharmony_ci#include "STG4000Interface.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* SDRAM fixed settings */ 2162306a36Sopenharmony_ci#define SDRAM_CFG_0 0x49A1 2262306a36Sopenharmony_ci#define SDRAM_CFG_1 0xA732 2362306a36Sopenharmony_ci#define SDRAM_CFG_2 0x31 2462306a36Sopenharmony_ci#define SDRAM_ARB_CFG 0xA0 2562306a36Sopenharmony_ci#define SDRAM_REFRESH 0x20 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Reset values */ 2862306a36Sopenharmony_ci#define PMX2_SOFTRESET_DAC_RST 0x0001 2962306a36Sopenharmony_ci#define PMX2_SOFTRESET_C1_RST 0x0004 3062306a36Sopenharmony_ci#define PMX2_SOFTRESET_C2_RST 0x0008 3162306a36Sopenharmony_ci#define PMX2_SOFTRESET_3D_RST 0x0010 3262306a36Sopenharmony_ci#define PMX2_SOFTRESET_VIDIN_RST 0x0020 3362306a36Sopenharmony_ci#define PMX2_SOFTRESET_TLB_RST 0x0040 3462306a36Sopenharmony_ci#define PMX2_SOFTRESET_SD_RST 0x0080 3562306a36Sopenharmony_ci#define PMX2_SOFTRESET_VGA_RST 0x0100 3662306a36Sopenharmony_ci#define PMX2_SOFTRESET_ROM_RST 0x0200 /* reserved bit, do not reset */ 3762306a36Sopenharmony_ci#define PMX2_SOFTRESET_TA_RST 0x0400 3862306a36Sopenharmony_ci#define PMX2_SOFTRESET_REG_RST 0x4000 3962306a36Sopenharmony_ci#define PMX2_SOFTRESET_ALL 0x7fff 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Core clock freq */ 4262306a36Sopenharmony_ci#define CORE_PLL_FREQ 1000000 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Reference Clock freq */ 4562306a36Sopenharmony_ci#define REF_FREQ 14318 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* PCI Registers */ 4862306a36Sopenharmony_cistatic u16 CorePllControl = 0x70; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define PCI_CONFIG_SUBSYS_ID 0x2e 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* Misc */ 5362306a36Sopenharmony_ci#define CORE_PLL_MODE_REG_0_7 3 5462306a36Sopenharmony_ci#define CORE_PLL_MODE_REG_8_15 2 5562306a36Sopenharmony_ci#define CORE_PLL_MODE_CONFIG_REG 1 5662306a36Sopenharmony_ci#define DAC_PLL_CONFIG_REG 0 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define STG_MAX_VCO 500000 5962306a36Sopenharmony_ci#define STG_MIN_VCO 100000 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* PLL Clock */ 6262306a36Sopenharmony_ci#define STG4K3_PLL_SCALER 8 /* scale numbers by 2^8 for fixed point calc */ 6362306a36Sopenharmony_ci#define STG4K3_PLL_MIN_R 2 /* Minimum multiplier */ 6462306a36Sopenharmony_ci#define STG4K3_PLL_MAX_R 33 /* Max */ 6562306a36Sopenharmony_ci#define STG4K3_PLL_MIN_F 2 /* Minimum divisor */ 6662306a36Sopenharmony_ci#define STG4K3_PLL_MAX_F 513 /* Max */ 6762306a36Sopenharmony_ci#define STG4K3_PLL_MIN_OD 0 /* Min output divider (shift) */ 6862306a36Sopenharmony_ci#define STG4K3_PLL_MAX_OD 2 /* Max */ 6962306a36Sopenharmony_ci#define STG4K3_PLL_MIN_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate */ 7062306a36Sopenharmony_ci#define STG4K3_PLL_MAX_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate */ 7162306a36Sopenharmony_ci#define STG4K3_PLL_MINR_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate (restricted) */ 7262306a36Sopenharmony_ci#define STG4K3_PLL_MAXR_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate (restricted) */ 7362306a36Sopenharmony_ci#define STG4K3_PLL_MINR_VCO 100000000 /* Min VCO rate (restricted) */ 7462306a36Sopenharmony_ci#define STG4K3_PLL_MAX_VCO 500000000 /* Max VCO rate */ 7562306a36Sopenharmony_ci#define STG4K3_PLL_MAXR_VCO 500000000 /* Max VCO rate (restricted) */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define OS_DELAY(X) \ 7862306a36Sopenharmony_ci{ \ 7962306a36Sopenharmony_civolatile u32 i,count=0; \ 8062306a36Sopenharmony_ci for(i=0;i<X;i++) count++; \ 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg, 8462306a36Sopenharmony_ci u32 dwSubSysID, u32 dwRevID) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci static const u8 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 }; 8762306a36Sopenharmony_ci static const u16 adwSDRAMCfg1[] = { 0x8732, 0x8732, 0xa732, 0xa732, 0x8732 }; 8862306a36Sopenharmony_ci static const u16 adwSDRAMCfg2[] = { 0x87d2, 0x87d2, 0xa7d2, 0x87d2, 0xa7d2 }; 8962306a36Sopenharmony_ci static const u8 adwSDRAMRsh[] = { 36, 39, 40 }; 9062306a36Sopenharmony_ci static const u8 adwChipSpeed[] = { 110, 120, 125 }; 9162306a36Sopenharmony_ci u32 dwMemTypeIdx; 9262306a36Sopenharmony_ci u32 dwChipSpeedIdx; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Get memory tpye and chip speed indexs from the SubSysDevID */ 9562306a36Sopenharmony_ci dwMemTypeIdx = (dwSubSysID & 0x70) >> 4; 9662306a36Sopenharmony_ci dwChipSpeedIdx = (dwSubSysID & 0x180) >> 7; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (dwMemTypeIdx > 4 || dwChipSpeedIdx > 2) 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Program SD-RAM interface */ 10262306a36Sopenharmony_ci STG_WRITE_REG(SDRAMArbiterConf, adwSDRAMArgCfg0[dwMemTypeIdx]); 10362306a36Sopenharmony_ci if (dwRevID < 5) { 10462306a36Sopenharmony_ci STG_WRITE_REG(SDRAMConf0, 0x49A1); 10562306a36Sopenharmony_ci STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg1[dwMemTypeIdx]); 10662306a36Sopenharmony_ci } else { 10762306a36Sopenharmony_ci STG_WRITE_REG(SDRAMConf0, 0x4DF1); 10862306a36Sopenharmony_ci STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg2[dwMemTypeIdx]); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci STG_WRITE_REG(SDRAMConf2, 0x31); 11262306a36Sopenharmony_ci STG_WRITE_REG(SDRAMRefresh, adwSDRAMRsh[dwChipSpeedIdx]); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return adwChipSpeed[dwChipSpeedIdx] * 10000; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciu32 ProgramClock(u32 refClock, 11862306a36Sopenharmony_ci u32 coreClock, 11962306a36Sopenharmony_ci u32 * FOut, u32 * ROut, u32 * POut) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci u32 R = 0, F = 0, OD = 0, ODIndex = 0; 12262306a36Sopenharmony_ci u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0; 12362306a36Sopenharmony_ci u32 ulBestClk = 0, ulBestScore = 0; 12462306a36Sopenharmony_ci u32 ulScore, ulPhaseScore, ulVcoScore; 12562306a36Sopenharmony_ci u32 ulTmp = 0, ulVCO; 12662306a36Sopenharmony_ci u32 ulScaleClockReq, ulMinClock, ulMaxClock; 12762306a36Sopenharmony_ci static const unsigned char ODValues[] = { 1, 2, 0 }; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Translate clock in Hz */ 13062306a36Sopenharmony_ci coreClock *= 100; /* in Hz */ 13162306a36Sopenharmony_ci refClock *= 1000; /* in Hz */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Work out acceptable clock 13462306a36Sopenharmony_ci * The method calculates ~ +- 0.4% (1/256) 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci ulMinClock = coreClock - (coreClock >> 8); 13762306a36Sopenharmony_ci ulMaxClock = coreClock + (coreClock >> 8); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Scale clock required for use in calculations */ 14062306a36Sopenharmony_ci ulScaleClockReq = coreClock >> STG4K3_PLL_SCALER; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Iterate through post divider values */ 14362306a36Sopenharmony_ci for (ODIndex = 0; ODIndex < 3; ODIndex++) { 14462306a36Sopenharmony_ci OD = ODValues[ODIndex]; 14562306a36Sopenharmony_ci R = STG4K3_PLL_MIN_R; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* loop for pre-divider from min to max */ 14862306a36Sopenharmony_ci while (R <= STG4K3_PLL_MAX_R) { 14962306a36Sopenharmony_ci /* estimate required feedback multiplier */ 15062306a36Sopenharmony_ci ulTmp = R * (ulScaleClockReq << OD); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* F = ClkRequired * R * (2^OD) / Fref */ 15362306a36Sopenharmony_ci F = (u32)(ulTmp / (refClock >> STG4K3_PLL_SCALER)); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* compensate for accuracy */ 15662306a36Sopenharmony_ci if (F > STG4K3_PLL_MIN_F) 15762306a36Sopenharmony_ci F--; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * We should be close to our target frequency (if it's 16262306a36Sopenharmony_ci * achievable with current OD & R) let's iterate 16362306a36Sopenharmony_ci * through F for best fit 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci while ((F >= STG4K3_PLL_MIN_F) && 16662306a36Sopenharmony_ci (F <= STG4K3_PLL_MAX_F)) { 16762306a36Sopenharmony_ci /* Calc VCO at full accuracy */ 16862306a36Sopenharmony_ci ulVCO = refClock / R; 16962306a36Sopenharmony_ci ulVCO = F * ulVCO; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* 17262306a36Sopenharmony_ci * Check it's within restricted VCO range 17362306a36Sopenharmony_ci * unless of course the desired frequency is 17462306a36Sopenharmony_ci * above the restricted range, then test 17562306a36Sopenharmony_ci * against VCO limit 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci if ((ulVCO >= STG4K3_PLL_MINR_VCO) && 17862306a36Sopenharmony_ci ((ulVCO <= STG4K3_PLL_MAXR_VCO) || 17962306a36Sopenharmony_ci ((coreClock > STG4K3_PLL_MAXR_VCO) 18062306a36Sopenharmony_ci && (ulVCO <= STG4K3_PLL_MAX_VCO)))) { 18162306a36Sopenharmony_ci ulTmp = (ulVCO >> OD); /* Clock = VCO / (2^OD) */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Is this clock good enough? */ 18462306a36Sopenharmony_ci if ((ulTmp >= ulMinClock) 18562306a36Sopenharmony_ci && (ulTmp <= ulMaxClock)) { 18662306a36Sopenharmony_ci ulPhaseScore = (((refClock / R) - (refClock / STG4K3_PLL_MAX_R))) / ((refClock - (refClock / STG4K3_PLL_MAX_R)) >> 10); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ulVcoScore = ((ulVCO - STG4K3_PLL_MINR_VCO)) / ((STG4K3_PLL_MAXR_VCO - STG4K3_PLL_MINR_VCO) >> 10); 18962306a36Sopenharmony_ci ulScore = ulPhaseScore + ulVcoScore; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (!ulBestScore) { 19262306a36Sopenharmony_ci ulBestOD = OD; 19362306a36Sopenharmony_ci ulBestF = F; 19462306a36Sopenharmony_ci ulBestR = R; 19562306a36Sopenharmony_ci ulBestClk = ulTmp; 19662306a36Sopenharmony_ci ulBestScore = 19762306a36Sopenharmony_ci ulScore; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci /* is this better, ( aim for highest Score) */ 20062306a36Sopenharmony_ci /*-------------------------------------------------------------------------- 20162306a36Sopenharmony_ci Here we want to use a scoring system which will take account of both the 20262306a36Sopenharmony_ci value at the phase comparater and the VCO output 20362306a36Sopenharmony_ci to do this we will use a cumulative score between the two 20462306a36Sopenharmony_ci The way this ends up is that we choose the first value in the loop anyway 20562306a36Sopenharmony_ci but we shall keep this code in case new restrictions come into play 20662306a36Sopenharmony_ci --------------------------------------------------------------------------*/ 20762306a36Sopenharmony_ci if ((ulScore >= ulBestScore) && (OD > 0)) { 20862306a36Sopenharmony_ci ulBestOD = OD; 20962306a36Sopenharmony_ci ulBestF = F; 21062306a36Sopenharmony_ci ulBestR = R; 21162306a36Sopenharmony_ci ulBestClk = ulTmp; 21262306a36Sopenharmony_ci ulBestScore = 21362306a36Sopenharmony_ci ulScore; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci F++; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci R++; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci did we find anything? 22562306a36Sopenharmony_ci Then return RFOD 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci if (ulBestScore) { 22862306a36Sopenharmony_ci *ROut = ulBestR; 22962306a36Sopenharmony_ci *FOut = ulBestF; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if ((ulBestOD == 2) || (ulBestOD == 3)) { 23262306a36Sopenharmony_ci *POut = 3; 23362306a36Sopenharmony_ci } else 23462306a36Sopenharmony_ci *POut = ulBestOD; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return (ulBestClk); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ciint SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci u32 F, R, P; 24462306a36Sopenharmony_ci u16 core_pll = 0, sub; 24562306a36Sopenharmony_ci u32 tmp; 24662306a36Sopenharmony_ci u32 ulChipSpeed; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci STG_WRITE_REG(IntMask, 0xFFFF); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Disable Primary Core Thread0 */ 25162306a36Sopenharmony_ci tmp = STG_READ_REG(Thread0Enable); 25262306a36Sopenharmony_ci CLEAR_BIT(0); 25362306a36Sopenharmony_ci STG_WRITE_REG(Thread0Enable, tmp); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Disable Primary Core Thread1 */ 25662306a36Sopenharmony_ci tmp = STG_READ_REG(Thread1Enable); 25762306a36Sopenharmony_ci CLEAR_BIT(0); 25862306a36Sopenharmony_ci STG_WRITE_REG(Thread1Enable, tmp); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci STG_WRITE_REG(SoftwareReset, 26162306a36Sopenharmony_ci PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); 26262306a36Sopenharmony_ci STG_WRITE_REG(SoftwareReset, 26362306a36Sopenharmony_ci PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | 26462306a36Sopenharmony_ci PMX2_SOFTRESET_ROM_RST); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Need to play around to reset TA */ 26762306a36Sopenharmony_ci STG_WRITE_REG(TAConfiguration, 0); 26862306a36Sopenharmony_ci STG_WRITE_REG(SoftwareReset, 26962306a36Sopenharmony_ci PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); 27062306a36Sopenharmony_ci STG_WRITE_REG(SoftwareReset, 27162306a36Sopenharmony_ci PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | 27262306a36Sopenharmony_ci PMX2_SOFTRESET_ROM_RST); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, 27762306a36Sopenharmony_ci (u32)pDev->revision); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (ulChipSpeed == 0) 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11)); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Set Core PLL Control to Core PLL Mode */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Send bits 0:7 of the Core PLL Mode register */ 28962306a36Sopenharmony_ci tmp = ((CORE_PLL_MODE_REG_0_7 << 8) | (core_pll & 0x00FF)); 29062306a36Sopenharmony_ci pci_write_config_word(pDev, CorePllControl, tmp); 29162306a36Sopenharmony_ci /* Without some delay between the PCI config writes the clock does 29262306a36Sopenharmony_ci not reliably set when the code is compiled -O3 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci OS_DELAY(1000000); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci tmp |= SET_BIT(14); 29762306a36Sopenharmony_ci pci_write_config_word(pDev, CorePllControl, tmp); 29862306a36Sopenharmony_ci OS_DELAY(1000000); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Send bits 8:15 of the Core PLL Mode register */ 30162306a36Sopenharmony_ci tmp = 30262306a36Sopenharmony_ci ((CORE_PLL_MODE_REG_8_15 << 8) | ((core_pll & 0xFF00) >> 8)); 30362306a36Sopenharmony_ci pci_write_config_word(pDev, CorePllControl, tmp); 30462306a36Sopenharmony_ci OS_DELAY(1000000); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci tmp |= SET_BIT(14); 30762306a36Sopenharmony_ci pci_write_config_word(pDev, CorePllControl, tmp); 30862306a36Sopenharmony_ci OS_DELAY(1000000); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci STG_WRITE_REG(SoftwareReset, PMX2_SOFTRESET_ALL); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci#if 0 31362306a36Sopenharmony_ci /* Enable Primary Core Thread0 */ 31462306a36Sopenharmony_ci tmp = ((STG_READ_REG(Thread0Enable)) | SET_BIT(0)); 31562306a36Sopenharmony_ci STG_WRITE_REG(Thread0Enable, tmp); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Enable Primary Core Thread1 */ 31862306a36Sopenharmony_ci tmp = ((STG_READ_REG(Thread1Enable)) | SET_BIT(0)); 31962306a36Sopenharmony_ci STG_WRITE_REG(Thread1Enable, tmp); 32062306a36Sopenharmony_ci#endif 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 324