617 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2021-2022, 2024, Qualcomm Innovation Center, Inc. All rights reserved.4 * Copyright (c) 2023, Linaro Limited5 */6 7#include <linux/clk-provider.h>8#include <linux/err.h>9#include <linux/kernel.h>10#include <linux/mod_devicetable.h>11#include <linux/module.h>12#include <linux/platform_device.h>13#include <linux/regmap.h>14 15#include <dt-bindings/clock/qcom,sa8775p-gpucc.h>16 17#include "clk-alpha-pll.h"18#include "clk-branch.h"19#include "clk-rcg.h"20#include "clk-regmap.h"21#include "clk-regmap-divider.h"22#include "common.h"23#include "reset.h"24#include "gdsc.h"25 26/* Need to match the order of clocks in DT binding */27enum {28 DT_BI_TCXO,29 DT_GCC_GPU_GPLL0_CLK_SRC,30 DT_GCC_GPU_GPLL0_DIV_CLK_SRC,31};32 33enum {34 P_BI_TCXO,35 P_GPLL0_OUT_MAIN,36 P_GPLL0_OUT_MAIN_DIV,37 P_GPU_CC_PLL0_OUT_MAIN,38 P_GPU_CC_PLL1_OUT_MAIN,39};40 41static const struct clk_parent_data parent_data_tcxo = { .index = DT_BI_TCXO };42 43static const struct pll_vco lucid_evo_vco[] = {44 { 249600000, 2020000000, 0 },45};46 47/* 810MHz configuration */48static struct alpha_pll_config gpu_cc_pll0_config = {49 .l = 0x2a,50 .alpha = 0x3000,51 .config_ctl_val = 0x20485699,52 .config_ctl_hi_val = 0x00182261,53 .config_ctl_hi1_val = 0x32aa299c,54 .user_ctl_val = 0x00000001,55 .user_ctl_hi_val = 0x00400805,56};57 58static struct clk_alpha_pll gpu_cc_pll0 = {59 .offset = 0x0,60 .vco_table = lucid_evo_vco,61 .num_vco = ARRAY_SIZE(lucid_evo_vco),62 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],63 .clkr = {64 .hw.init = &(const struct clk_init_data){65 .name = "gpu_cc_pll0",66 .parent_data = &parent_data_tcxo,67 .num_parents = 1,68 .ops = &clk_alpha_pll_lucid_evo_ops,69 },70 },71};72 73/* 1000MHz configuration */74static struct alpha_pll_config gpu_cc_pll1_config = {75 .l = 0x34,76 .alpha = 0x1555,77 .config_ctl_val = 0x20485699,78 .config_ctl_hi_val = 0x00182261,79 .config_ctl_hi1_val = 0x32aa299c,80 .user_ctl_val = 0x00000001,81 .user_ctl_hi_val = 0x00400805,82};83 84static struct clk_alpha_pll gpu_cc_pll1 = {85 .offset = 0x1000,86 .vco_table = lucid_evo_vco,87 .num_vco = ARRAY_SIZE(lucid_evo_vco),88 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],89 .clkr = {90 .hw.init = &(const struct clk_init_data){91 .name = "gpu_cc_pll1",92 .parent_data = &parent_data_tcxo,93 .num_parents = 1,94 .ops = &clk_alpha_pll_lucid_evo_ops,95 },96 },97};98 99static const struct parent_map gpu_cc_parent_map_0[] = {100 { P_BI_TCXO, 0 },101 { P_GPLL0_OUT_MAIN, 5 },102 { P_GPLL0_OUT_MAIN_DIV, 6 },103};104 105static const struct clk_parent_data gpu_cc_parent_data_0[] = {106 { .index = DT_BI_TCXO },107 { .index = DT_GCC_GPU_GPLL0_CLK_SRC },108 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC },109};110 111static const struct parent_map gpu_cc_parent_map_1[] = {112 { P_BI_TCXO, 0 },113 { P_GPU_CC_PLL0_OUT_MAIN, 1 },114 { P_GPU_CC_PLL1_OUT_MAIN, 3 },115 { P_GPLL0_OUT_MAIN, 5 },116 { P_GPLL0_OUT_MAIN_DIV, 6 },117};118 119static const struct clk_parent_data gpu_cc_parent_data_1[] = {120 { .index = DT_BI_TCXO },121 { .hw = &gpu_cc_pll0.clkr.hw },122 { .hw = &gpu_cc_pll1.clkr.hw },123 { .index = DT_GCC_GPU_GPLL0_CLK_SRC },124 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC },125};126 127static const struct parent_map gpu_cc_parent_map_2[] = {128 { P_BI_TCXO, 0 },129 { P_GPU_CC_PLL1_OUT_MAIN, 3 },130 { P_GPLL0_OUT_MAIN, 5 },131 { P_GPLL0_OUT_MAIN_DIV, 6 },132};133 134static const struct clk_parent_data gpu_cc_parent_data_2[] = {135 { .index = DT_BI_TCXO },136 { .hw = &gpu_cc_pll1.clkr.hw },137 { .index = DT_GCC_GPU_GPLL0_CLK_SRC },138 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC },139};140 141static const struct parent_map gpu_cc_parent_map_3[] = {142 { P_BI_TCXO, 0 },143};144 145static const struct clk_parent_data gpu_cc_parent_data_3[] = {146 { .index = DT_BI_TCXO },147};148 149static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = {150 F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),151 { }152};153 154static struct clk_rcg2 gpu_cc_ff_clk_src = {155 .cmd_rcgr = 0x9474,156 .mnd_width = 0,157 .hid_width = 5,158 .parent_map = gpu_cc_parent_map_0,159 .freq_tbl = ftbl_gpu_cc_ff_clk_src,160 .clkr.hw.init = &(const struct clk_init_data){161 .name = "gpu_cc_ff_clk_src",162 .parent_data = gpu_cc_parent_data_0,163 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),164 .ops = &clk_rcg2_shared_ops,165 },166};167 168static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {169 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0),170 { }171};172 173static struct clk_rcg2 gpu_cc_gmu_clk_src = {174 .cmd_rcgr = 0x9318,175 .mnd_width = 0,176 .hid_width = 5,177 .parent_map = gpu_cc_parent_map_1,178 .freq_tbl = ftbl_gpu_cc_gmu_clk_src,179 .clkr.hw.init = &(const struct clk_init_data){180 .name = "gpu_cc_gmu_clk_src",181 .parent_data = gpu_cc_parent_data_1,182 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),183 .flags = CLK_SET_RATE_PARENT,184 .ops = &clk_rcg2_shared_ops,185 },186};187 188static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = {189 F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),190 { }191};192 193static struct clk_rcg2 gpu_cc_hub_clk_src = {194 .cmd_rcgr = 0x93ec,195 .mnd_width = 0,196 .hid_width = 5,197 .parent_map = gpu_cc_parent_map_2,198 .freq_tbl = ftbl_gpu_cc_hub_clk_src,199 .clkr.hw.init = &(const struct clk_init_data){200 .name = "gpu_cc_hub_clk_src",201 .parent_data = gpu_cc_parent_data_2,202 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2),203 .ops = &clk_rcg2_shared_ops,204 },205};206 207static const struct freq_tbl ftbl_gpu_cc_xo_clk_src[] = {208 F(19200000, P_BI_TCXO, 1, 0, 0),209 { }210};211 212static struct clk_rcg2 gpu_cc_xo_clk_src = {213 .cmd_rcgr = 0x9010,214 .mnd_width = 0,215 .hid_width = 5,216 .parent_map = gpu_cc_parent_map_3,217 .freq_tbl = ftbl_gpu_cc_xo_clk_src,218 .clkr.hw.init = &(const struct clk_init_data){219 .name = "gpu_cc_xo_clk_src",220 .parent_data = gpu_cc_parent_data_3,221 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_3),222 .ops = &clk_rcg2_ops,223 },224};225 226static struct clk_regmap_div gpu_cc_demet_div_clk_src = {227 .reg = 0x9054,228 .shift = 0,229 .width = 4,230 .clkr.hw.init = &(const struct clk_init_data) {231 .name = "gpu_cc_demet_div_clk_src",232 .parent_hws = (const struct clk_hw*[]){233 &gpu_cc_xo_clk_src.clkr.hw,234 },235 .num_parents = 1,236 .flags = CLK_SET_RATE_PARENT,237 .ops = &clk_regmap_div_ro_ops,238 },239};240 241static struct clk_regmap_div gpu_cc_hub_ahb_div_clk_src = {242 .reg = 0x9430,243 .shift = 0,244 .width = 4,245 .clkr.hw.init = &(const struct clk_init_data) {246 .name = "gpu_cc_hub_ahb_div_clk_src",247 .parent_hws = (const struct clk_hw*[]){248 &gpu_cc_hub_clk_src.clkr.hw,249 },250 .num_parents = 1,251 .flags = CLK_SET_RATE_PARENT,252 .ops = &clk_regmap_div_ro_ops,253 },254};255 256static struct clk_regmap_div gpu_cc_hub_cx_int_div_clk_src = {257 .reg = 0x942c,258 .shift = 0,259 .width = 4,260 .clkr.hw.init = &(const struct clk_init_data) {261 .name = "gpu_cc_hub_cx_int_div_clk_src",262 .parent_hws = (const struct clk_hw*[]){263 &gpu_cc_hub_clk_src.clkr.hw,264 },265 .num_parents = 1,266 .flags = CLK_SET_RATE_PARENT,267 .ops = &clk_regmap_div_ro_ops,268 },269};270 271static struct clk_branch gpu_cc_ahb_clk = {272 .halt_reg = 0x911c,273 .halt_check = BRANCH_HALT_DELAY,274 .clkr = {275 .enable_reg = 0x911c,276 .enable_mask = BIT(0),277 .hw.init = &(const struct clk_init_data){278 .name = "gpu_cc_ahb_clk",279 .parent_hws = (const struct clk_hw*[]){280 &gpu_cc_hub_ahb_div_clk_src.clkr.hw,281 },282 .num_parents = 1,283 .flags = CLK_SET_RATE_PARENT,284 .ops = &clk_branch2_ops,285 },286 },287};288 289static struct clk_branch gpu_cc_cb_clk = {290 .halt_reg = 0x93a4,291 .halt_check = BRANCH_HALT,292 .clkr = {293 .enable_reg = 0x93a4,294 .enable_mask = BIT(0),295 .hw.init = &(const struct clk_init_data){296 .name = "gpu_cc_cb_clk",297 .ops = &clk_branch2_aon_ops,298 },299 },300};301 302static struct clk_branch gpu_cc_crc_ahb_clk = {303 .halt_reg = 0x9120,304 .halt_check = BRANCH_HALT_VOTED,305 .clkr = {306 .enable_reg = 0x9120,307 .enable_mask = BIT(0),308 .hw.init = &(const struct clk_init_data){309 .name = "gpu_cc_crc_ahb_clk",310 .parent_hws = (const struct clk_hw*[]){311 &gpu_cc_hub_ahb_div_clk_src.clkr.hw,312 },313 .num_parents = 1,314 .flags = CLK_SET_RATE_PARENT,315 .ops = &clk_branch2_ops,316 },317 },318};319 320static struct clk_branch gpu_cc_cx_ff_clk = {321 .halt_reg = 0x914c,322 .halt_check = BRANCH_HALT,323 .clkr = {324 .enable_reg = 0x914c,325 .enable_mask = BIT(0),326 .hw.init = &(const struct clk_init_data){327 .name = "gpu_cc_cx_ff_clk",328 .parent_hws = (const struct clk_hw*[]){329 &gpu_cc_ff_clk_src.clkr.hw,330 },331 .num_parents = 1,332 .flags = CLK_SET_RATE_PARENT,333 .ops = &clk_branch2_ops,334 },335 },336};337 338static struct clk_branch gpu_cc_cx_gmu_clk = {339 .halt_reg = 0x913c,340 .halt_check = BRANCH_HALT,341 .clkr = {342 .enable_reg = 0x913c,343 .enable_mask = BIT(0),344 .hw.init = &(const struct clk_init_data){345 .name = "gpu_cc_cx_gmu_clk",346 .parent_hws = (const struct clk_hw*[]){347 &gpu_cc_gmu_clk_src.clkr.hw,348 },349 .num_parents = 1,350 .flags = CLK_SET_RATE_PARENT,351 .ops = &clk_branch2_aon_ops,352 },353 },354};355 356static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {357 .halt_reg = 0x9130,358 .halt_check = BRANCH_HALT_VOTED,359 .clkr = {360 .enable_reg = 0x9130,361 .enable_mask = BIT(0),362 .hw.init = &(const struct clk_init_data){363 .name = "gpu_cc_cx_snoc_dvm_clk",364 .ops = &clk_branch2_ops,365 },366 },367};368 369static struct clk_branch gpu_cc_cxo_aon_clk = {370 .halt_reg = 0x9004,371 .halt_check = BRANCH_HALT_VOTED,372 .clkr = {373 .enable_reg = 0x9004,374 .enable_mask = BIT(0),375 .hw.init = &(const struct clk_init_data){376 .name = "gpu_cc_cxo_aon_clk",377 .parent_hws = (const struct clk_hw*[]){378 &gpu_cc_xo_clk_src.clkr.hw,379 },380 .num_parents = 1,381 .flags = CLK_SET_RATE_PARENT,382 .ops = &clk_branch2_ops,383 },384 },385};386 387static struct clk_branch gpu_cc_cxo_clk = {388 .halt_reg = 0x9144,389 .halt_check = BRANCH_HALT,390 .clkr = {391 .enable_reg = 0x9144,392 .enable_mask = BIT(0),393 .hw.init = &(const struct clk_init_data){394 .name = "gpu_cc_cxo_clk",395 .parent_hws = (const struct clk_hw*[]){396 &gpu_cc_xo_clk_src.clkr.hw,397 },398 .num_parents = 1,399 .flags = CLK_SET_RATE_PARENT,400 .ops = &clk_branch2_ops,401 },402 },403};404 405static struct clk_branch gpu_cc_demet_clk = {406 .halt_reg = 0x900c,407 .halt_check = BRANCH_HALT,408 .clkr = {409 .enable_reg = 0x900c,410 .enable_mask = BIT(0),411 .hw.init = &(const struct clk_init_data){412 .name = "gpu_cc_demet_clk",413 .parent_hws = (const struct clk_hw*[]){414 &gpu_cc_demet_div_clk_src.clkr.hw,415 },416 .num_parents = 1,417 .flags = CLK_SET_RATE_PARENT,418 .ops = &clk_branch2_aon_ops,419 },420 },421};422 423static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {424 .halt_reg = 0x7000,425 .halt_check = BRANCH_HALT_VOTED,426 .clkr = {427 .enable_reg = 0x7000,428 .enable_mask = BIT(0),429 .hw.init = &(const struct clk_init_data){430 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",431 .ops = &clk_branch2_ops,432 },433 },434};435 436static struct clk_branch gpu_cc_hub_aon_clk = {437 .halt_reg = 0x93e8,438 .halt_check = BRANCH_HALT,439 .clkr = {440 .enable_reg = 0x93e8,441 .enable_mask = BIT(0),442 .hw.init = &(const struct clk_init_data){443 .name = "gpu_cc_hub_aon_clk",444 .parent_hws = (const struct clk_hw*[]){445 &gpu_cc_hub_clk_src.clkr.hw,446 },447 .num_parents = 1,448 .flags = CLK_SET_RATE_PARENT,449 .ops = &clk_branch2_aon_ops,450 },451 },452};453 454static struct clk_branch gpu_cc_hub_cx_int_clk = {455 .halt_reg = 0x9148,456 .halt_check = BRANCH_HALT,457 .clkr = {458 .enable_reg = 0x9148,459 .enable_mask = BIT(0),460 .hw.init = &(const struct clk_init_data){461 .name = "gpu_cc_hub_cx_int_clk",462 .parent_hws = (const struct clk_hw*[]){463 &gpu_cc_hub_cx_int_div_clk_src.clkr.hw,464 },465 .num_parents = 1,466 .flags = CLK_SET_RATE_PARENT,467 .ops = &clk_branch2_aon_ops,468 },469 },470};471 472static struct clk_branch gpu_cc_memnoc_gfx_clk = {473 .halt_reg = 0x9150,474 .halt_check = BRANCH_HALT,475 .clkr = {476 .enable_reg = 0x9150,477 .enable_mask = BIT(0),478 .hw.init = &(const struct clk_init_data){479 .name = "gpu_cc_memnoc_gfx_clk",480 .ops = &clk_branch2_ops,481 },482 },483};484 485static struct clk_branch gpu_cc_sleep_clk = {486 .halt_reg = 0x9134,487 .halt_check = BRANCH_HALT_VOTED,488 .clkr = {489 .enable_reg = 0x9134,490 .enable_mask = BIT(0),491 .hw.init = &(const struct clk_init_data){492 .name = "gpu_cc_sleep_clk",493 .ops = &clk_branch2_ops,494 },495 },496};497 498static struct clk_regmap *gpu_cc_sa8775p_clocks[] = {499 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,500 [GPU_CC_CB_CLK] = &gpu_cc_cb_clk.clkr,501 [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,502 [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr,503 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,504 [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,505 [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,506 [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,507 [GPU_CC_DEMET_CLK] = &gpu_cc_demet_clk.clkr,508 [GPU_CC_DEMET_DIV_CLK_SRC] = &gpu_cc_demet_div_clk_src.clkr,509 [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr,510 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,511 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,512 [GPU_CC_HUB_AHB_DIV_CLK_SRC] = &gpu_cc_hub_ahb_div_clk_src.clkr,513 [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,514 [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,515 [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,516 [GPU_CC_HUB_CX_INT_DIV_CLK_SRC] = &gpu_cc_hub_cx_int_div_clk_src.clkr,517 [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr,518 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,519 [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,520 [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr,521 [GPU_CC_XO_CLK_SRC] = &gpu_cc_xo_clk_src.clkr,522};523 524static struct gdsc cx_gdsc = {525 .gdscr = 0x9108,526 .en_rest_wait_val = 0x2,527 .en_few_wait_val = 0x2,528 .clk_dis_wait_val = 0xf,529 .gds_hw_ctrl = 0x953c,530 .pd = {531 .name = "cx_gdsc",532 },533 .pwrsts = PWRSTS_OFF_ON,534 .flags = VOTABLE | RETAIN_FF_ENABLE,535};536 537static struct gdsc gx_gdsc = {538 .gdscr = 0x905c,539 .en_rest_wait_val = 0x2,540 .en_few_wait_val = 0x2,541 .clk_dis_wait_val = 0xf,542 .pd = {543 .name = "gx_gdsc",544 .power_on = gdsc_gx_do_nothing_enable,545 },546 .pwrsts = PWRSTS_OFF_ON,547 .flags = AON_RESET | RETAIN_FF_ENABLE,548};549 550static struct gdsc *gpu_cc_sa8775p_gdscs[] = {551 [GPU_CC_CX_GDSC] = &cx_gdsc,552 [GPU_CC_GX_GDSC] = &gx_gdsc,553};554 555static const struct qcom_reset_map gpu_cc_sa8775p_resets[] = {556 [GPUCC_GPU_CC_ACD_BCR] = { 0x9358 },557 [GPUCC_GPU_CC_CB_BCR] = { 0x93a0 },558 [GPUCC_GPU_CC_CX_BCR] = { 0x9104 },559 [GPUCC_GPU_CC_FAST_HUB_BCR] = { 0x93e4 },560 [GPUCC_GPU_CC_FF_BCR] = { 0x9470 },561 [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x9198 },562 [GPUCC_GPU_CC_GMU_BCR] = { 0x9314 },563 [GPUCC_GPU_CC_GX_BCR] = { 0x9058 },564 [GPUCC_GPU_CC_XO_BCR] = { 0x9000 },565};566 567static const struct regmap_config gpu_cc_sa8775p_regmap_config = {568 .reg_bits = 32,569 .reg_stride = 4,570 .val_bits = 32,571 .max_register = 0x9988,572 .fast_io = true,573};574 575static const struct qcom_cc_desc gpu_cc_sa8775p_desc = {576 .config = &gpu_cc_sa8775p_regmap_config,577 .clks = gpu_cc_sa8775p_clocks,578 .num_clks = ARRAY_SIZE(gpu_cc_sa8775p_clocks),579 .resets = gpu_cc_sa8775p_resets,580 .num_resets = ARRAY_SIZE(gpu_cc_sa8775p_resets),581 .gdscs = gpu_cc_sa8775p_gdscs,582 .num_gdscs = ARRAY_SIZE(gpu_cc_sa8775p_gdscs),583};584 585static const struct of_device_id gpu_cc_sa8775p_match_table[] = {586 { .compatible = "qcom,sa8775p-gpucc" },587 { }588};589MODULE_DEVICE_TABLE(of, gpu_cc_sa8775p_match_table);590 591static int gpu_cc_sa8775p_probe(struct platform_device *pdev)592{593 struct regmap *regmap;594 595 regmap = qcom_cc_map(pdev, &gpu_cc_sa8775p_desc);596 if (IS_ERR(regmap))597 return PTR_ERR(regmap);598 599 clk_lucid_evo_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);600 clk_lucid_evo_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);601 602 return qcom_cc_really_probe(&pdev->dev, &gpu_cc_sa8775p_desc, regmap);603}604 605static struct platform_driver gpu_cc_sa8775p_driver = {606 .probe = gpu_cc_sa8775p_probe,607 .driver = {608 .name = "gpu_cc-sa8775p",609 .of_match_table = gpu_cc_sa8775p_match_table,610 },611};612 613module_platform_driver(gpu_cc_sa8775p_driver);614 615MODULE_DESCRIPTION("SA8775P GPUCC driver");616MODULE_LICENSE("GPL");617