13a580e9eSGhennadi Procopciuc /* 23a580e9eSGhennadi Procopciuc * Copyright 2024 NXP 33a580e9eSGhennadi Procopciuc * 43a580e9eSGhennadi Procopciuc * SPDX-License-Identifier: BSD-3-Clause 53a580e9eSGhennadi Procopciuc */ 63a580e9eSGhennadi Procopciuc #include <errno.h> 73a580e9eSGhennadi Procopciuc 88ab34357SGhennadi Procopciuc #include <s32cc-clk-regs.h> 98ab34357SGhennadi Procopciuc 10d9373519SGhennadi Procopciuc #include <common/debug.h> 113a580e9eSGhennadi Procopciuc #include <drivers/clk.h> 128ab34357SGhennadi Procopciuc #include <lib/mmio.h> 13d9373519SGhennadi Procopciuc #include <s32cc-clk-modules.h> 14d9373519SGhennadi Procopciuc #include <s32cc-clk-utils.h> 15d9373519SGhennadi Procopciuc 16d9373519SGhennadi Procopciuc #define MAX_STACK_DEPTH (15U) 17d9373519SGhennadi Procopciuc 188ab34357SGhennadi Procopciuc struct s32cc_clk_drv { 198ab34357SGhennadi Procopciuc uintptr_t fxosc_base; 208ab34357SGhennadi Procopciuc }; 218ab34357SGhennadi Procopciuc 22d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth) 23d9373519SGhennadi Procopciuc { 24d9373519SGhennadi Procopciuc if (*depth == 0U) { 25d9373519SGhennadi Procopciuc return -ENOMEM; 26d9373519SGhennadi Procopciuc } 27d9373519SGhennadi Procopciuc 28d9373519SGhennadi Procopciuc (*depth)--; 29d9373519SGhennadi Procopciuc return 0; 30d9373519SGhennadi Procopciuc } 313a580e9eSGhennadi Procopciuc 328ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void) 338ab34357SGhennadi Procopciuc { 348ab34357SGhennadi Procopciuc static struct s32cc_clk_drv driver = { 358ab34357SGhennadi Procopciuc .fxosc_base = FXOSC_BASE_ADDR, 368ab34357SGhennadi Procopciuc }; 378ab34357SGhennadi Procopciuc 388ab34357SGhennadi Procopciuc return &driver; 398ab34357SGhennadi Procopciuc } 408ab34357SGhennadi Procopciuc 418ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth); 428ab34357SGhennadi Procopciuc 438ab34357SGhennadi Procopciuc static int enable_clk_module(const struct s32cc_clk_obj *module, 448ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 458ab34357SGhennadi Procopciuc unsigned int *depth) 468ab34357SGhennadi Procopciuc { 478ab34357SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 488ab34357SGhennadi Procopciuc int ret; 498ab34357SGhennadi Procopciuc 508ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 518ab34357SGhennadi Procopciuc if (ret != 0) { 528ab34357SGhennadi Procopciuc return ret; 538ab34357SGhennadi Procopciuc } 548ab34357SGhennadi Procopciuc 558ab34357SGhennadi Procopciuc if (clk == NULL) { 568ab34357SGhennadi Procopciuc return -EINVAL; 578ab34357SGhennadi Procopciuc } 588ab34357SGhennadi Procopciuc 598ab34357SGhennadi Procopciuc if (clk->module != NULL) { 608ab34357SGhennadi Procopciuc return enable_module(clk->module, depth); 618ab34357SGhennadi Procopciuc } 628ab34357SGhennadi Procopciuc 638ab34357SGhennadi Procopciuc if (clk->pclock != NULL) { 648ab34357SGhennadi Procopciuc return enable_clk_module(&clk->pclock->desc, drv, depth); 658ab34357SGhennadi Procopciuc } 668ab34357SGhennadi Procopciuc 678ab34357SGhennadi Procopciuc return -EINVAL; 688ab34357SGhennadi Procopciuc } 698ab34357SGhennadi Procopciuc 708ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv) 718ab34357SGhennadi Procopciuc { 728ab34357SGhennadi Procopciuc uintptr_t fxosc_base = drv->fxosc_base; 738ab34357SGhennadi Procopciuc uint32_t ctrl; 748ab34357SGhennadi Procopciuc 758ab34357SGhennadi Procopciuc ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base)); 768ab34357SGhennadi Procopciuc if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) { 778ab34357SGhennadi Procopciuc return; 788ab34357SGhennadi Procopciuc } 798ab34357SGhennadi Procopciuc 808ab34357SGhennadi Procopciuc ctrl = FXOSC_CTRL_COMP_EN; 818ab34357SGhennadi Procopciuc ctrl &= ~FXOSC_CTRL_OSC_BYP; 828ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_EOCV(0x1); 838ab34357SGhennadi Procopciuc ctrl |= FXOSC_CTRL_GM_SEL(0x7); 848ab34357SGhennadi Procopciuc mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl); 858ab34357SGhennadi Procopciuc 868ab34357SGhennadi Procopciuc /* Switch ON the crystal oscillator. */ 878ab34357SGhennadi Procopciuc mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON); 888ab34357SGhennadi Procopciuc 898ab34357SGhennadi Procopciuc /* Wait until the clock is stable. */ 908ab34357SGhennadi Procopciuc while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) { 918ab34357SGhennadi Procopciuc } 928ab34357SGhennadi Procopciuc } 938ab34357SGhennadi Procopciuc 948ab34357SGhennadi Procopciuc static int enable_osc(const struct s32cc_clk_obj *module, 958ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv, 968ab34357SGhennadi Procopciuc unsigned int *depth) 978ab34357SGhennadi Procopciuc { 988ab34357SGhennadi Procopciuc const struct s32cc_osc *osc = s32cc_obj2osc(module); 998ab34357SGhennadi Procopciuc int ret = 0; 1008ab34357SGhennadi Procopciuc 1018ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1028ab34357SGhennadi Procopciuc if (ret != 0) { 1038ab34357SGhennadi Procopciuc return ret; 1048ab34357SGhennadi Procopciuc } 1058ab34357SGhennadi Procopciuc 1068ab34357SGhennadi Procopciuc switch (osc->source) { 1078ab34357SGhennadi Procopciuc case S32CC_FXOSC: 1088ab34357SGhennadi Procopciuc enable_fxosc(drv); 1098ab34357SGhennadi Procopciuc break; 1108ab34357SGhennadi Procopciuc /* FIRC and SIRC oscillators are enabled by default */ 1118ab34357SGhennadi Procopciuc case S32CC_FIRC: 1128ab34357SGhennadi Procopciuc break; 1138ab34357SGhennadi Procopciuc case S32CC_SIRC: 1148ab34357SGhennadi Procopciuc break; 1158ab34357SGhennadi Procopciuc default: 1168ab34357SGhennadi Procopciuc ERROR("Invalid oscillator %d\n", osc->source); 1178ab34357SGhennadi Procopciuc ret = -EINVAL; 1188ab34357SGhennadi Procopciuc break; 1198ab34357SGhennadi Procopciuc }; 1208ab34357SGhennadi Procopciuc 1218ab34357SGhennadi Procopciuc return ret; 1228ab34357SGhennadi Procopciuc } 1238ab34357SGhennadi Procopciuc 1248ab34357SGhennadi Procopciuc static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth) 1258ab34357SGhennadi Procopciuc { 1268ab34357SGhennadi Procopciuc const struct s32cc_clk_drv *drv = get_drv(); 1278ab34357SGhennadi Procopciuc int ret = 0; 1288ab34357SGhennadi Procopciuc 1298ab34357SGhennadi Procopciuc ret = update_stack_depth(depth); 1308ab34357SGhennadi Procopciuc if (ret != 0) { 1318ab34357SGhennadi Procopciuc return ret; 1328ab34357SGhennadi Procopciuc } 1338ab34357SGhennadi Procopciuc 1348ab34357SGhennadi Procopciuc if (drv == NULL) { 1358ab34357SGhennadi Procopciuc return -EINVAL; 1368ab34357SGhennadi Procopciuc } 1378ab34357SGhennadi Procopciuc 1388ab34357SGhennadi Procopciuc switch (module->type) { 1398ab34357SGhennadi Procopciuc case s32cc_osc_t: 1408ab34357SGhennadi Procopciuc ret = enable_osc(module, drv, depth); 1418ab34357SGhennadi Procopciuc break; 1428ab34357SGhennadi Procopciuc case s32cc_clk_t: 1438ab34357SGhennadi Procopciuc ret = enable_clk_module(module, drv, depth); 1448ab34357SGhennadi Procopciuc break; 145a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 146a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 147a8be748aSGhennadi Procopciuc break; 148*3fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 149*3fa91a94SGhennadi Procopciuc ret = -ENOTSUP; 150*3fa91a94SGhennadi Procopciuc break; 151a8be748aSGhennadi Procopciuc case s32cc_pll_t: 152a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 153a8be748aSGhennadi Procopciuc break; 154a8be748aSGhennadi Procopciuc case s32cc_pll_out_div_t: 155a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 156a8be748aSGhennadi Procopciuc break; 1578ab34357SGhennadi Procopciuc default: 1588ab34357SGhennadi Procopciuc ret = -EINVAL; 1598ab34357SGhennadi Procopciuc break; 1608ab34357SGhennadi Procopciuc } 1618ab34357SGhennadi Procopciuc 1628ab34357SGhennadi Procopciuc return ret; 1638ab34357SGhennadi Procopciuc } 1648ab34357SGhennadi Procopciuc 1653a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id) 1663a580e9eSGhennadi Procopciuc { 1678ab34357SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 1688ab34357SGhennadi Procopciuc const struct s32cc_clk *clk; 1698ab34357SGhennadi Procopciuc 1708ab34357SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 1718ab34357SGhennadi Procopciuc if (clk == NULL) { 1728ab34357SGhennadi Procopciuc return -EINVAL; 1738ab34357SGhennadi Procopciuc } 1748ab34357SGhennadi Procopciuc 1758ab34357SGhennadi Procopciuc return enable_module(&clk->desc, &depth); 1763a580e9eSGhennadi Procopciuc } 1773a580e9eSGhennadi Procopciuc 1783a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id) 1793a580e9eSGhennadi Procopciuc { 1803a580e9eSGhennadi Procopciuc } 1813a580e9eSGhennadi Procopciuc 1823a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id) 1833a580e9eSGhennadi Procopciuc { 1843a580e9eSGhennadi Procopciuc return false; 1853a580e9eSGhennadi Procopciuc } 1863a580e9eSGhennadi Procopciuc 1873a580e9eSGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id) 1883a580e9eSGhennadi Procopciuc { 1893a580e9eSGhennadi Procopciuc return 0; 1903a580e9eSGhennadi Procopciuc } 1913a580e9eSGhennadi Procopciuc 192d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 193d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 194d9373519SGhennadi Procopciuc unsigned int *depth); 195d9373519SGhennadi Procopciuc 196d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate, 197d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 198d9373519SGhennadi Procopciuc { 199d9373519SGhennadi Procopciuc struct s32cc_osc *osc = s32cc_obj2osc(module); 200d9373519SGhennadi Procopciuc int ret; 201d9373519SGhennadi Procopciuc 202d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 203d9373519SGhennadi Procopciuc if (ret != 0) { 204d9373519SGhennadi Procopciuc return ret; 205d9373519SGhennadi Procopciuc } 206d9373519SGhennadi Procopciuc 207d9373519SGhennadi Procopciuc if ((osc->freq != 0UL) && (rate != osc->freq)) { 208d9373519SGhennadi Procopciuc ERROR("Already initialized oscillator. freq = %lu\n", 209d9373519SGhennadi Procopciuc osc->freq); 210d9373519SGhennadi Procopciuc return -EINVAL; 211d9373519SGhennadi Procopciuc } 212d9373519SGhennadi Procopciuc 213d9373519SGhennadi Procopciuc osc->freq = rate; 214d9373519SGhennadi Procopciuc *orate = osc->freq; 215d9373519SGhennadi Procopciuc 216d9373519SGhennadi Procopciuc return 0; 217d9373519SGhennadi Procopciuc } 218d9373519SGhennadi Procopciuc 219d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate, 220d9373519SGhennadi Procopciuc unsigned long *orate, unsigned int *depth) 221d9373519SGhennadi Procopciuc { 222d9373519SGhennadi Procopciuc const struct s32cc_clk *clk = s32cc_obj2clk(module); 223d9373519SGhennadi Procopciuc int ret; 224d9373519SGhennadi Procopciuc 225d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 226d9373519SGhennadi Procopciuc if (ret != 0) { 227d9373519SGhennadi Procopciuc return ret; 228d9373519SGhennadi Procopciuc } 229d9373519SGhennadi Procopciuc 230d9373519SGhennadi Procopciuc if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) && 231d9373519SGhennadi Procopciuc ((rate < clk->min_freq) || (rate > clk->max_freq))) { 232d9373519SGhennadi Procopciuc ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n", 233d9373519SGhennadi Procopciuc rate, clk->min_freq, clk->max_freq); 234d9373519SGhennadi Procopciuc return -EINVAL; 235d9373519SGhennadi Procopciuc } 236d9373519SGhennadi Procopciuc 237d9373519SGhennadi Procopciuc if (clk->module != NULL) { 238d9373519SGhennadi Procopciuc return set_module_rate(clk->module, rate, orate, depth); 239d9373519SGhennadi Procopciuc } 240d9373519SGhennadi Procopciuc 241d9373519SGhennadi Procopciuc if (clk->pclock != NULL) { 242d9373519SGhennadi Procopciuc return set_clk_freq(&clk->pclock->desc, rate, orate, depth); 243d9373519SGhennadi Procopciuc } 244d9373519SGhennadi Procopciuc 245d9373519SGhennadi Procopciuc return -EINVAL; 246d9373519SGhennadi Procopciuc } 247d9373519SGhennadi Procopciuc 248d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module, 249d9373519SGhennadi Procopciuc unsigned long rate, unsigned long *orate, 250d9373519SGhennadi Procopciuc unsigned int *depth) 251d9373519SGhennadi Procopciuc { 252d9373519SGhennadi Procopciuc int ret = 0; 253d9373519SGhennadi Procopciuc 254d9373519SGhennadi Procopciuc ret = update_stack_depth(depth); 255d9373519SGhennadi Procopciuc if (ret != 0) { 256d9373519SGhennadi Procopciuc return ret; 257d9373519SGhennadi Procopciuc } 258d9373519SGhennadi Procopciuc 259d9373519SGhennadi Procopciuc switch (module->type) { 260d9373519SGhennadi Procopciuc case s32cc_clk_t: 261d9373519SGhennadi Procopciuc ret = set_clk_freq(module, rate, orate, depth); 262d9373519SGhennadi Procopciuc break; 263d9373519SGhennadi Procopciuc case s32cc_osc_t: 264d9373519SGhennadi Procopciuc ret = set_osc_freq(module, rate, orate, depth); 265d9373519SGhennadi Procopciuc break; 266a8be748aSGhennadi Procopciuc case s32cc_clkmux_t: 267*3fa91a94SGhennadi Procopciuc case s32cc_shared_clkmux_t: 268a8be748aSGhennadi Procopciuc case s32cc_pll_t: 269a8be748aSGhennadi Procopciuc case s32cc_pll_out_div_t: 270a8be748aSGhennadi Procopciuc ret = -ENOTSUP; 271a8be748aSGhennadi Procopciuc break; 272d9373519SGhennadi Procopciuc default: 273d9373519SGhennadi Procopciuc ret = -EINVAL; 274d9373519SGhennadi Procopciuc break; 275d9373519SGhennadi Procopciuc } 276d9373519SGhennadi Procopciuc 277d9373519SGhennadi Procopciuc return ret; 278d9373519SGhennadi Procopciuc } 279d9373519SGhennadi Procopciuc 2803a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate, 2813a580e9eSGhennadi Procopciuc unsigned long *orate) 2823a580e9eSGhennadi Procopciuc { 283d9373519SGhennadi Procopciuc unsigned int depth = MAX_STACK_DEPTH; 284d9373519SGhennadi Procopciuc const struct s32cc_clk *clk; 285d9373519SGhennadi Procopciuc int ret; 286d9373519SGhennadi Procopciuc 287d9373519SGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 288d9373519SGhennadi Procopciuc if (clk == NULL) { 289d9373519SGhennadi Procopciuc return -EINVAL; 290d9373519SGhennadi Procopciuc } 291d9373519SGhennadi Procopciuc 292d9373519SGhennadi Procopciuc ret = set_module_rate(&clk->desc, rate, orate, &depth); 293d9373519SGhennadi Procopciuc if (ret != 0) { 294d9373519SGhennadi Procopciuc ERROR("Failed to set frequency (%lu MHz) for clock %lu\n", 295d9373519SGhennadi Procopciuc rate, id); 296d9373519SGhennadi Procopciuc } 297d9373519SGhennadi Procopciuc 298d9373519SGhennadi Procopciuc return ret; 2993a580e9eSGhennadi Procopciuc } 3003a580e9eSGhennadi Procopciuc 3013a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id) 3023a580e9eSGhennadi Procopciuc { 3033a580e9eSGhennadi Procopciuc return -ENOTSUP; 3043a580e9eSGhennadi Procopciuc } 3053a580e9eSGhennadi Procopciuc 3063a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id) 3073a580e9eSGhennadi Procopciuc { 30812e7a2cdSGhennadi Procopciuc const struct s32cc_clk *parent; 30912e7a2cdSGhennadi Procopciuc const struct s32cc_clk *clk; 31012e7a2cdSGhennadi Procopciuc bool valid_source = false; 31112e7a2cdSGhennadi Procopciuc struct s32cc_clkmux *mux; 31212e7a2cdSGhennadi Procopciuc uint8_t i; 31312e7a2cdSGhennadi Procopciuc 31412e7a2cdSGhennadi Procopciuc clk = s32cc_get_arch_clk(id); 31512e7a2cdSGhennadi Procopciuc if (clk == NULL) { 31612e7a2cdSGhennadi Procopciuc return -EINVAL; 31712e7a2cdSGhennadi Procopciuc } 31812e7a2cdSGhennadi Procopciuc 31912e7a2cdSGhennadi Procopciuc parent = s32cc_get_arch_clk(parent_id); 32012e7a2cdSGhennadi Procopciuc if (parent == NULL) { 32112e7a2cdSGhennadi Procopciuc return -EINVAL; 32212e7a2cdSGhennadi Procopciuc } 32312e7a2cdSGhennadi Procopciuc 32412e7a2cdSGhennadi Procopciuc if (!is_s32cc_clk_mux(clk)) { 32512e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a mux\n", id); 32612e7a2cdSGhennadi Procopciuc return -EINVAL; 32712e7a2cdSGhennadi Procopciuc } 32812e7a2cdSGhennadi Procopciuc 32912e7a2cdSGhennadi Procopciuc mux = s32cc_clk2mux(clk); 33012e7a2cdSGhennadi Procopciuc if (mux == NULL) { 33112e7a2cdSGhennadi Procopciuc ERROR("Failed to cast clock %lu to clock mux\n", id); 33212e7a2cdSGhennadi Procopciuc return -EINVAL; 33312e7a2cdSGhennadi Procopciuc } 33412e7a2cdSGhennadi Procopciuc 33512e7a2cdSGhennadi Procopciuc for (i = 0; i < mux->nclks; i++) { 33612e7a2cdSGhennadi Procopciuc if (mux->clkids[i] == parent_id) { 33712e7a2cdSGhennadi Procopciuc valid_source = true; 33812e7a2cdSGhennadi Procopciuc break; 33912e7a2cdSGhennadi Procopciuc } 34012e7a2cdSGhennadi Procopciuc } 34112e7a2cdSGhennadi Procopciuc 34212e7a2cdSGhennadi Procopciuc if (!valid_source) { 34312e7a2cdSGhennadi Procopciuc ERROR("Clock %lu is not a valid clock for mux %lu\n", 34412e7a2cdSGhennadi Procopciuc parent_id, id); 34512e7a2cdSGhennadi Procopciuc return -EINVAL; 34612e7a2cdSGhennadi Procopciuc } 34712e7a2cdSGhennadi Procopciuc 34812e7a2cdSGhennadi Procopciuc mux->source_id = parent_id; 34912e7a2cdSGhennadi Procopciuc 35012e7a2cdSGhennadi Procopciuc return 0; 3513a580e9eSGhennadi Procopciuc } 3523a580e9eSGhennadi Procopciuc 3533a580e9eSGhennadi Procopciuc void s32cc_clk_register_drv(void) 3543a580e9eSGhennadi Procopciuc { 3553a580e9eSGhennadi Procopciuc static const struct clk_ops s32cc_clk_ops = { 3563a580e9eSGhennadi Procopciuc .enable = s32cc_clk_enable, 3573a580e9eSGhennadi Procopciuc .disable = s32cc_clk_disable, 3583a580e9eSGhennadi Procopciuc .is_enabled = s32cc_clk_is_enabled, 3593a580e9eSGhennadi Procopciuc .get_rate = s32cc_clk_get_rate, 3603a580e9eSGhennadi Procopciuc .set_rate = s32cc_clk_set_rate, 3613a580e9eSGhennadi Procopciuc .get_parent = s32cc_clk_get_parent, 3623a580e9eSGhennadi Procopciuc .set_parent = s32cc_clk_set_parent, 3633a580e9eSGhennadi Procopciuc }; 3643a580e9eSGhennadi Procopciuc 3653a580e9eSGhennadi Procopciuc clk_register(&s32cc_clk_ops); 3663a580e9eSGhennadi Procopciuc } 3673a580e9eSGhennadi Procopciuc 368