1*f6a8abe0STaniya Das // SPDX-License-Identifier: GPL-2.0-only 2*f6a8abe0STaniya Das /* 3*f6a8abe0STaniya Das * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. 4*f6a8abe0STaniya Das */ 5*f6a8abe0STaniya Das 6*f6a8abe0STaniya Das #include <linux/clk-provider.h> 7*f6a8abe0STaniya Das #include <linux/module.h> 8*f6a8abe0STaniya Das #include <linux/mod_devicetable.h> 9*f6a8abe0STaniya Das #include <linux/of.h> 10*f6a8abe0STaniya Das #include <linux/platform_device.h> 11*f6a8abe0STaniya Das #include <linux/regmap.h> 12*f6a8abe0STaniya Das 13*f6a8abe0STaniya Das #include <dt-bindings/clock/qcom,qcs615-videocc.h> 14*f6a8abe0STaniya Das 15*f6a8abe0STaniya Das #include "clk-alpha-pll.h" 16*f6a8abe0STaniya Das #include "clk-branch.h" 17*f6a8abe0STaniya Das #include "clk-pll.h" 18*f6a8abe0STaniya Das #include "clk-rcg.h" 19*f6a8abe0STaniya Das #include "clk-regmap.h" 20*f6a8abe0STaniya Das #include "clk-regmap-divider.h" 21*f6a8abe0STaniya Das #include "clk-regmap-mux.h" 22*f6a8abe0STaniya Das #include "common.h" 23*f6a8abe0STaniya Das #include "gdsc.h" 24*f6a8abe0STaniya Das #include "reset.h" 25*f6a8abe0STaniya Das 26*f6a8abe0STaniya Das enum { 27*f6a8abe0STaniya Das DT_BI_TCXO, 28*f6a8abe0STaniya Das DT_SLEEP_CLK, 29*f6a8abe0STaniya Das }; 30*f6a8abe0STaniya Das 31*f6a8abe0STaniya Das enum { 32*f6a8abe0STaniya Das P_BI_TCXO, 33*f6a8abe0STaniya Das P_SLEEP_CLK, 34*f6a8abe0STaniya Das P_VIDEO_PLL0_OUT_AUX, 35*f6a8abe0STaniya Das P_VIDEO_PLL0_OUT_AUX2, 36*f6a8abe0STaniya Das P_VIDEO_PLL0_OUT_MAIN, 37*f6a8abe0STaniya Das }; 38*f6a8abe0STaniya Das 39*f6a8abe0STaniya Das static const struct pll_vco video_cc_pll0_vco[] = { 40*f6a8abe0STaniya Das { 500000000, 1000000000, 2 }, 41*f6a8abe0STaniya Das }; 42*f6a8abe0STaniya Das 43*f6a8abe0STaniya Das /* 600MHz configuration VCO - 2 */ 44*f6a8abe0STaniya Das static struct alpha_pll_config video_pll0_config = { 45*f6a8abe0STaniya Das .l = 0x1f, 46*f6a8abe0STaniya Das .alpha_hi = 0x40, 47*f6a8abe0STaniya Das .alpha = 0x00, 48*f6a8abe0STaniya Das .alpha_en_mask = BIT(24), 49*f6a8abe0STaniya Das .vco_val = BIT(21), 50*f6a8abe0STaniya Das .vco_mask = GENMASK(21, 20), 51*f6a8abe0STaniya Das .main_output_mask = BIT(0), 52*f6a8abe0STaniya Das .config_ctl_val = 0x4001055b, 53*f6a8abe0STaniya Das .test_ctl_hi_val = 0x1, 54*f6a8abe0STaniya Das .test_ctl_hi_mask = 0x1, 55*f6a8abe0STaniya Das }; 56*f6a8abe0STaniya Das 57*f6a8abe0STaniya Das static struct clk_alpha_pll video_pll0 = { 58*f6a8abe0STaniya Das .offset = 0x42c, 59*f6a8abe0STaniya Das .config = &video_pll0_config, 60*f6a8abe0STaniya Das .vco_table = video_cc_pll0_vco, 61*f6a8abe0STaniya Das .num_vco = ARRAY_SIZE(video_cc_pll0_vco), 62*f6a8abe0STaniya Das .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 63*f6a8abe0STaniya Das .clkr = { 64*f6a8abe0STaniya Das .hw.init = &(const struct clk_init_data) { 65*f6a8abe0STaniya Das .name = "video_pll0", 66*f6a8abe0STaniya Das .parent_data = &(const struct clk_parent_data) { 67*f6a8abe0STaniya Das .index = DT_BI_TCXO, 68*f6a8abe0STaniya Das }, 69*f6a8abe0STaniya Das .num_parents = 1, 70*f6a8abe0STaniya Das .ops = &clk_alpha_pll_slew_ops, 71*f6a8abe0STaniya Das }, 72*f6a8abe0STaniya Das }, 73*f6a8abe0STaniya Das }; 74*f6a8abe0STaniya Das 75*f6a8abe0STaniya Das static const struct parent_map video_cc_parent_map_0[] = { 76*f6a8abe0STaniya Das { P_SLEEP_CLK, 0 }, 77*f6a8abe0STaniya Das }; 78*f6a8abe0STaniya Das 79*f6a8abe0STaniya Das static const struct clk_parent_data video_cc_parent_data_0_ao[] = { 80*f6a8abe0STaniya Das { .index = DT_SLEEP_CLK }, 81*f6a8abe0STaniya Das }; 82*f6a8abe0STaniya Das 83*f6a8abe0STaniya Das static const struct parent_map video_cc_parent_map_1[] = { 84*f6a8abe0STaniya Das { P_BI_TCXO, 0 }, 85*f6a8abe0STaniya Das { P_VIDEO_PLL0_OUT_MAIN, 1 }, 86*f6a8abe0STaniya Das { P_VIDEO_PLL0_OUT_AUX, 2 }, 87*f6a8abe0STaniya Das { P_VIDEO_PLL0_OUT_AUX2, 3 }, 88*f6a8abe0STaniya Das }; 89*f6a8abe0STaniya Das 90*f6a8abe0STaniya Das static const struct clk_parent_data video_cc_parent_data_1[] = { 91*f6a8abe0STaniya Das { .index = DT_BI_TCXO }, 92*f6a8abe0STaniya Das { .hw = &video_pll0.clkr.hw }, 93*f6a8abe0STaniya Das { .hw = &video_pll0.clkr.hw }, 94*f6a8abe0STaniya Das { .hw = &video_pll0.clkr.hw }, 95*f6a8abe0STaniya Das }; 96*f6a8abe0STaniya Das 97*f6a8abe0STaniya Das static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = { 98*f6a8abe0STaniya Das F(32000, P_SLEEP_CLK, 1, 0, 0), 99*f6a8abe0STaniya Das { } 100*f6a8abe0STaniya Das }; 101*f6a8abe0STaniya Das 102*f6a8abe0STaniya Das static struct clk_rcg2 video_cc_sleep_clk_src = { 103*f6a8abe0STaniya Das .cmd_rcgr = 0xaf8, 104*f6a8abe0STaniya Das .mnd_width = 0, 105*f6a8abe0STaniya Das .hid_width = 5, 106*f6a8abe0STaniya Das .parent_map = video_cc_parent_map_0, 107*f6a8abe0STaniya Das .freq_tbl = ftbl_video_cc_sleep_clk_src, 108*f6a8abe0STaniya Das .clkr.hw.init = &(const struct clk_init_data) { 109*f6a8abe0STaniya Das .name = "video_cc_sleep_clk_src", 110*f6a8abe0STaniya Das .parent_data = video_cc_parent_data_0_ao, 111*f6a8abe0STaniya Das .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao), 112*f6a8abe0STaniya Das .ops = &clk_rcg2_ops, 113*f6a8abe0STaniya Das }, 114*f6a8abe0STaniya Das }; 115*f6a8abe0STaniya Das 116*f6a8abe0STaniya Das static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { 117*f6a8abe0STaniya Das F(19200000, P_BI_TCXO, 1, 0, 0), 118*f6a8abe0STaniya Das F(133333333, P_VIDEO_PLL0_OUT_MAIN, 4.5, 0, 0), 119*f6a8abe0STaniya Das F(240000000, P_VIDEO_PLL0_OUT_MAIN, 2.5, 0, 0), 120*f6a8abe0STaniya Das F(300000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 121*f6a8abe0STaniya Das F(380000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 122*f6a8abe0STaniya Das F(410000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 123*f6a8abe0STaniya Das F(460000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), 124*f6a8abe0STaniya Das { } 125*f6a8abe0STaniya Das }; 126*f6a8abe0STaniya Das 127*f6a8abe0STaniya Das static struct clk_rcg2 video_cc_venus_clk_src = { 128*f6a8abe0STaniya Das .cmd_rcgr = 0x7f0, 129*f6a8abe0STaniya Das .mnd_width = 0, 130*f6a8abe0STaniya Das .hid_width = 5, 131*f6a8abe0STaniya Das .parent_map = video_cc_parent_map_1, 132*f6a8abe0STaniya Das .freq_tbl = ftbl_video_cc_venus_clk_src, 133*f6a8abe0STaniya Das .clkr.hw.init = &(const struct clk_init_data) { 134*f6a8abe0STaniya Das .name = "video_cc_venus_clk_src", 135*f6a8abe0STaniya Das .parent_data = video_cc_parent_data_1, 136*f6a8abe0STaniya Das .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 137*f6a8abe0STaniya Das .flags = CLK_SET_RATE_PARENT, 138*f6a8abe0STaniya Das .ops = &clk_rcg2_shared_ops, 139*f6a8abe0STaniya Das }, 140*f6a8abe0STaniya Das }; 141*f6a8abe0STaniya Das 142*f6a8abe0STaniya Das static struct clk_branch video_cc_sleep_clk = { 143*f6a8abe0STaniya Das .halt_reg = 0xb18, 144*f6a8abe0STaniya Das .halt_check = BRANCH_HALT, 145*f6a8abe0STaniya Das .clkr = { 146*f6a8abe0STaniya Das .enable_reg = 0xb18, 147*f6a8abe0STaniya Das .enable_mask = BIT(0), 148*f6a8abe0STaniya Das .hw.init = &(struct clk_init_data){ 149*f6a8abe0STaniya Das .name = "video_cc_sleep_clk", 150*f6a8abe0STaniya Das .parent_data = &(const struct clk_parent_data){ 151*f6a8abe0STaniya Das .hw = &video_cc_sleep_clk_src.clkr.hw, 152*f6a8abe0STaniya Das }, 153*f6a8abe0STaniya Das .num_parents = 1, 154*f6a8abe0STaniya Das .flags = CLK_SET_RATE_PARENT, 155*f6a8abe0STaniya Das .ops = &clk_branch2_ops, 156*f6a8abe0STaniya Das }, 157*f6a8abe0STaniya Das }, 158*f6a8abe0STaniya Das }; 159*f6a8abe0STaniya Das 160*f6a8abe0STaniya Das static struct clk_branch video_cc_vcodec0_axi_clk = { 161*f6a8abe0STaniya Das .halt_reg = 0x8f0, 162*f6a8abe0STaniya Das .halt_check = BRANCH_HALT, 163*f6a8abe0STaniya Das .clkr = { 164*f6a8abe0STaniya Das .enable_reg = 0x8f0, 165*f6a8abe0STaniya Das .enable_mask = BIT(0), 166*f6a8abe0STaniya Das .hw.init = &(const struct clk_init_data) { 167*f6a8abe0STaniya Das .name = "video_cc_vcodec0_axi_clk", 168*f6a8abe0STaniya Das .ops = &clk_branch2_ops, 169*f6a8abe0STaniya Das }, 170*f6a8abe0STaniya Das }, 171*f6a8abe0STaniya Das }; 172*f6a8abe0STaniya Das 173*f6a8abe0STaniya Das static struct clk_branch video_cc_vcodec0_core_clk = { 174*f6a8abe0STaniya Das .halt_reg = 0x890, 175*f6a8abe0STaniya Das .halt_check = BRANCH_HALT_VOTED, 176*f6a8abe0STaniya Das .clkr = { 177*f6a8abe0STaniya Das .enable_reg = 0x890, 178*f6a8abe0STaniya Das .enable_mask = BIT(0), 179*f6a8abe0STaniya Das .hw.init = &(const struct clk_init_data) { 180*f6a8abe0STaniya Das .name = "video_cc_vcodec0_core_clk", 181*f6a8abe0STaniya Das .parent_hws = (const struct clk_hw*[]) { 182*f6a8abe0STaniya Das &video_cc_venus_clk_src.clkr.hw, 183*f6a8abe0STaniya Das }, 184*f6a8abe0STaniya Das .num_parents = 1, 185*f6a8abe0STaniya Das .flags = CLK_SET_RATE_PARENT, 186*f6a8abe0STaniya Das .ops = &clk_branch2_ops, 187*f6a8abe0STaniya Das }, 188*f6a8abe0STaniya Das }, 189*f6a8abe0STaniya Das }; 190*f6a8abe0STaniya Das 191*f6a8abe0STaniya Das static struct clk_branch video_cc_venus_ahb_clk = { 192*f6a8abe0STaniya Das .halt_reg = 0x9b0, 193*f6a8abe0STaniya Das .halt_check = BRANCH_HALT, 194*f6a8abe0STaniya Das .clkr = { 195*f6a8abe0STaniya Das .enable_reg = 0x9b0, 196*f6a8abe0STaniya Das .enable_mask = BIT(0), 197*f6a8abe0STaniya Das .hw.init = &(const struct clk_init_data) { 198*f6a8abe0STaniya Das .name = "video_cc_venus_ahb_clk", 199*f6a8abe0STaniya Das .ops = &clk_branch2_ops, 200*f6a8abe0STaniya Das }, 201*f6a8abe0STaniya Das }, 202*f6a8abe0STaniya Das }; 203*f6a8abe0STaniya Das 204*f6a8abe0STaniya Das static struct clk_branch video_cc_venus_ctl_axi_clk = { 205*f6a8abe0STaniya Das .halt_reg = 0x8d0, 206*f6a8abe0STaniya Das .halt_check = BRANCH_HALT, 207*f6a8abe0STaniya Das .clkr = { 208*f6a8abe0STaniya Das .enable_reg = 0x8d0, 209*f6a8abe0STaniya Das .enable_mask = BIT(0), 210*f6a8abe0STaniya Das .hw.init = &(const struct clk_init_data) { 211*f6a8abe0STaniya Das .name = "video_cc_venus_ctl_axi_clk", 212*f6a8abe0STaniya Das .ops = &clk_branch2_ops, 213*f6a8abe0STaniya Das }, 214*f6a8abe0STaniya Das }, 215*f6a8abe0STaniya Das }; 216*f6a8abe0STaniya Das 217*f6a8abe0STaniya Das static struct clk_branch video_cc_venus_ctl_core_clk = { 218*f6a8abe0STaniya Das .halt_reg = 0x850, 219*f6a8abe0STaniya Das .halt_check = BRANCH_HALT, 220*f6a8abe0STaniya Das .clkr = { 221*f6a8abe0STaniya Das .enable_reg = 0x850, 222*f6a8abe0STaniya Das .enable_mask = BIT(0), 223*f6a8abe0STaniya Das .hw.init = &(const struct clk_init_data) { 224*f6a8abe0STaniya Das .name = "video_cc_venus_ctl_core_clk", 225*f6a8abe0STaniya Das .parent_hws = (const struct clk_hw*[]) { 226*f6a8abe0STaniya Das &video_cc_venus_clk_src.clkr.hw, 227*f6a8abe0STaniya Das }, 228*f6a8abe0STaniya Das .num_parents = 1, 229*f6a8abe0STaniya Das .flags = CLK_SET_RATE_PARENT, 230*f6a8abe0STaniya Das .ops = &clk_branch2_ops, 231*f6a8abe0STaniya Das }, 232*f6a8abe0STaniya Das }, 233*f6a8abe0STaniya Das }; 234*f6a8abe0STaniya Das 235*f6a8abe0STaniya Das static struct gdsc vcodec0_gdsc = { 236*f6a8abe0STaniya Das .gdscr = 0x874, 237*f6a8abe0STaniya Das .en_rest_wait_val = 0x2, 238*f6a8abe0STaniya Das .en_few_wait_val = 0x2, 239*f6a8abe0STaniya Das .clk_dis_wait_val = 0x6, 240*f6a8abe0STaniya Das .pd = { 241*f6a8abe0STaniya Das .name = "vcodec0_gdsc", 242*f6a8abe0STaniya Das }, 243*f6a8abe0STaniya Das .pwrsts = PWRSTS_OFF_ON, 244*f6a8abe0STaniya Das .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR, 245*f6a8abe0STaniya Das }; 246*f6a8abe0STaniya Das 247*f6a8abe0STaniya Das static struct gdsc venus_gdsc = { 248*f6a8abe0STaniya Das .gdscr = 0x814, 249*f6a8abe0STaniya Das .en_rest_wait_val = 0x2, 250*f6a8abe0STaniya Das .en_few_wait_val = 0x2, 251*f6a8abe0STaniya Das .clk_dis_wait_val = 0x6, 252*f6a8abe0STaniya Das .pd = { 253*f6a8abe0STaniya Das .name = "venus_gdsc", 254*f6a8abe0STaniya Das }, 255*f6a8abe0STaniya Das .pwrsts = PWRSTS_OFF_ON, 256*f6a8abe0STaniya Das .flags = POLL_CFG_GDSCR, 257*f6a8abe0STaniya Das }; 258*f6a8abe0STaniya Das 259*f6a8abe0STaniya Das static struct clk_regmap *video_cc_qcs615_clocks[] = { 260*f6a8abe0STaniya Das [VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr, 261*f6a8abe0STaniya Das [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr, 262*f6a8abe0STaniya Das [VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr, 263*f6a8abe0STaniya Das [VIDEO_CC_VCODEC0_CORE_CLK] = &video_cc_vcodec0_core_clk.clkr, 264*f6a8abe0STaniya Das [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, 265*f6a8abe0STaniya Das [VIDEO_CC_VENUS_CLK_SRC] = &video_cc_venus_clk_src.clkr, 266*f6a8abe0STaniya Das [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr, 267*f6a8abe0STaniya Das [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr, 268*f6a8abe0STaniya Das [VIDEO_PLL0] = &video_pll0.clkr, 269*f6a8abe0STaniya Das }; 270*f6a8abe0STaniya Das 271*f6a8abe0STaniya Das static struct gdsc *video_cc_qcs615_gdscs[] = { 272*f6a8abe0STaniya Das [VCODEC0_GDSC] = &vcodec0_gdsc, 273*f6a8abe0STaniya Das [VENUS_GDSC] = &venus_gdsc, 274*f6a8abe0STaniya Das }; 275*f6a8abe0STaniya Das 276*f6a8abe0STaniya Das static const struct qcom_reset_map video_cc_qcs615_resets[] = { 277*f6a8abe0STaniya Das [VIDEO_CC_INTERFACE_BCR] = { 0x8b0 }, 278*f6a8abe0STaniya Das [VIDEO_CC_VCODEC0_BCR] = { 0x870 }, 279*f6a8abe0STaniya Das [VIDEO_CC_VENUS_BCR] = { 0x810 }, 280*f6a8abe0STaniya Das }; 281*f6a8abe0STaniya Das 282*f6a8abe0STaniya Das static struct clk_alpha_pll *video_cc_qcs615_plls[] = { 283*f6a8abe0STaniya Das &video_pll0, 284*f6a8abe0STaniya Das }; 285*f6a8abe0STaniya Das 286*f6a8abe0STaniya Das static u32 video_cc_qcs615_critical_cbcrs[] = { 287*f6a8abe0STaniya Das 0xab8, /* VIDEO_CC_XO_CLK */ 288*f6a8abe0STaniya Das }; 289*f6a8abe0STaniya Das 290*f6a8abe0STaniya Das static const struct regmap_config video_cc_qcs615_regmap_config = { 291*f6a8abe0STaniya Das .reg_bits = 32, 292*f6a8abe0STaniya Das .reg_stride = 4, 293*f6a8abe0STaniya Das .val_bits = 32, 294*f6a8abe0STaniya Das .max_register = 0xb94, 295*f6a8abe0STaniya Das .fast_io = true, 296*f6a8abe0STaniya Das }; 297*f6a8abe0STaniya Das 298*f6a8abe0STaniya Das static struct qcom_cc_driver_data video_cc_qcs615_driver_data = { 299*f6a8abe0STaniya Das .alpha_plls = video_cc_qcs615_plls, 300*f6a8abe0STaniya Das .num_alpha_plls = ARRAY_SIZE(video_cc_qcs615_plls), 301*f6a8abe0STaniya Das .clk_cbcrs = video_cc_qcs615_critical_cbcrs, 302*f6a8abe0STaniya Das .num_clk_cbcrs = ARRAY_SIZE(video_cc_qcs615_critical_cbcrs), 303*f6a8abe0STaniya Das }; 304*f6a8abe0STaniya Das 305*f6a8abe0STaniya Das static const struct qcom_cc_desc video_cc_qcs615_desc = { 306*f6a8abe0STaniya Das .config = &video_cc_qcs615_regmap_config, 307*f6a8abe0STaniya Das .clks = video_cc_qcs615_clocks, 308*f6a8abe0STaniya Das .num_clks = ARRAY_SIZE(video_cc_qcs615_clocks), 309*f6a8abe0STaniya Das .resets = video_cc_qcs615_resets, 310*f6a8abe0STaniya Das .num_resets = ARRAY_SIZE(video_cc_qcs615_resets), 311*f6a8abe0STaniya Das .gdscs = video_cc_qcs615_gdscs, 312*f6a8abe0STaniya Das .num_gdscs = ARRAY_SIZE(video_cc_qcs615_gdscs), 313*f6a8abe0STaniya Das .driver_data = &video_cc_qcs615_driver_data, 314*f6a8abe0STaniya Das }; 315*f6a8abe0STaniya Das 316*f6a8abe0STaniya Das static const struct of_device_id video_cc_qcs615_match_table[] = { 317*f6a8abe0STaniya Das { .compatible = "qcom,qcs615-videocc" }, 318*f6a8abe0STaniya Das { } 319*f6a8abe0STaniya Das }; 320*f6a8abe0STaniya Das MODULE_DEVICE_TABLE(of, video_cc_qcs615_match_table); 321*f6a8abe0STaniya Das 322*f6a8abe0STaniya Das static int video_cc_qcs615_probe(struct platform_device *pdev) 323*f6a8abe0STaniya Das { 324*f6a8abe0STaniya Das return qcom_cc_probe(pdev, &video_cc_qcs615_desc); 325*f6a8abe0STaniya Das } 326*f6a8abe0STaniya Das 327*f6a8abe0STaniya Das static struct platform_driver video_cc_qcs615_driver = { 328*f6a8abe0STaniya Das .probe = video_cc_qcs615_probe, 329*f6a8abe0STaniya Das .driver = { 330*f6a8abe0STaniya Das .name = "videocc-qcs615", 331*f6a8abe0STaniya Das .of_match_table = video_cc_qcs615_match_table, 332*f6a8abe0STaniya Das }, 333*f6a8abe0STaniya Das }; 334*f6a8abe0STaniya Das 335*f6a8abe0STaniya Das module_platform_driver(video_cc_qcs615_driver); 336*f6a8abe0STaniya Das 337*f6a8abe0STaniya Das MODULE_DESCRIPTION("QTI VIDEOCC QCS615 Driver"); 338*f6a8abe0STaniya Das MODULE_LICENSE("GPL"); 339