ARM: AM33xx: Cleanup dplls data
authorLokesh Vutla <lokeshvutla@ti.com>
Tue, 30 Jul 2013 05:18:52 +0000 (10:48 +0530)
committerTom Rini <trini@ti.com>
Thu, 15 Aug 2013 12:51:10 +0000 (08:51 -0400)
Locking sequence for all the dplls is same.
In the current code same sequence is done repeatedly
for each dpll. Instead have a generic function
for locking dplls and pass dpll data to that function.

This is derived from OMAP4 boards.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Tested-by: Heiko Schocher <hs@denx.de>
Acked-by: Heiko Schocher <hs@denx.de>
arch/arm/cpu/armv7/am33xx/Makefile
arch/arm/cpu/armv7/am33xx/clock.c [new file with mode: 0644]
arch/arm/cpu/armv7/am33xx/clock_am33xx.c
arch/arm/cpu/armv7/am33xx/emif4.c
arch/arm/include/asm/arch-am33xx/clock.h
arch/arm/include/asm/arch-am33xx/ddr_defs.h
arch/arm/include/asm/arch-am33xx/sys_proto.h
board/isee/igep0033/board.c
board/phytec/pcm051/board.c
board/ti/am335x/board.c

index dbd1ec3..7fd21af 100644 (file)
@@ -10,6 +10,7 @@ LIB   = $(obj)lib$(SOC).o
 
 COBJS-$(CONFIG_AM33XX) += clock_am33xx.o
 COBJS-$(CONFIG_TI814X) += clock_ti814x.o
+COBJS-$(CONFIG_AM33XX) += clock.o
 COBJS  += sys_info.o
 COBJS  += mem.o
 COBJS  += ddr.o
diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c
new file mode 100644 (file)
index 0000000..15f4a2c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * clock.c
+ *
+ * Clock initialization for AM33XX boards.
+ * Derived from OMAP4 boards
+ *
+ * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+
+static void setup_post_dividers(const struct dpll_regs *dpll_regs,
+                        const struct dpll_params *params)
+{
+       /* Setup post-dividers */
+       if (params->m2 >= 0)
+               writel(params->m2, dpll_regs->cm_div_m2_dpll);
+       if (params->m3 >= 0)
+               writel(params->m3, dpll_regs->cm_div_m3_dpll);
+       if (params->m4 >= 0)
+               writel(params->m4, dpll_regs->cm_div_m4_dpll);
+       if (params->m5 >= 0)
+               writel(params->m5, dpll_regs->cm_div_m5_dpll);
+       if (params->m6 >= 0)
+               writel(params->m6, dpll_regs->cm_div_m6_dpll);
+}
+
+static inline void do_lock_dpll(const struct dpll_regs *dpll_regs)
+{
+       clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
+                       CM_CLKMODE_DPLL_DPLL_EN_MASK,
+                       DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
+}
+
+static inline void wait_for_lock(const struct dpll_regs *dpll_regs)
+{
+       if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
+                          (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
+               printf("DPLL locking failed for 0x%x\n",
+                      dpll_regs->cm_clkmode_dpll);
+               hang();
+       }
+}
+
+static inline void do_bypass_dpll(const struct dpll_regs *dpll_regs)
+{
+       clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
+                       CM_CLKMODE_DPLL_DPLL_EN_MASK,
+                       DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
+}
+
+static inline void wait_for_bypass(const struct dpll_regs *dpll_regs)
+{
+       if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
+                          (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
+               printf("Bypassing DPLL failed 0x%x\n",
+                      dpll_regs->cm_clkmode_dpll);
+       }
+}
+
+static void bypass_dpll(const struct dpll_regs *dpll_regs)
+{
+       do_bypass_dpll(dpll_regs);
+       wait_for_bypass(dpll_regs);
+}
+
+void do_setup_dpll(const struct dpll_regs *dpll_regs,
+                  const struct dpll_params *params)
+{
+       u32 temp;
+
+       if (!params)
+               return;
+
+       temp = readl(dpll_regs->cm_clksel_dpll);
+
+       bypass_dpll(dpll_regs);
+
+       /* Set M & N */
+       temp &= ~CM_CLKSEL_DPLL_M_MASK;
+       temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
+
+       temp &= ~CM_CLKSEL_DPLL_N_MASK;
+       temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
+
+       writel(temp, dpll_regs->cm_clksel_dpll);
+
+       setup_post_dividers(dpll_regs, params);
+
+       /* Wait till the DPLL locks */
+       do_lock_dpll(dpll_regs);
+       wait_for_lock(dpll_regs);
+}
+
+void setup_dplls(void)
+{
+       const struct dpll_params *params;
+       do_setup_dpll(&dpll_core_regs, &dpll_core);
+       do_setup_dpll(&dpll_mpu_regs, &dpll_mpu);
+       do_setup_dpll(&dpll_per_regs, &dpll_per);
+       writel(0x300, &cmwkup->clkdcoldodpllper);
+
+       params = get_dpll_ddr_params();
+       do_setup_dpll(&dpll_ddr_regs, params);
+}
index fb3fb43..d5d47ad 100644 (file)
 #define PRCM_FORCE_WAKEUP      0x2
 #define PRCM_FUNCTL            0x0
 
-#define PRCM_EMIF_CLK_ACTIVITY BIT(2)
-#define PRCM_L3_GCLK_ACTIVITY  BIT(4)
-
-#define PLL_BYPASS_MODE                0x4
-#define ST_MN_BYPASS           0x00000100
-#define ST_DPLL_CLK            0x00000001
-#define CLK_SEL_MASK           0x7ffff
-#define CLK_DIV_MASK           0x1f
-#define CLK_DIV2_MASK          0x7f
-#define CLK_SEL_SHIFT          0x8
-#define CLK_MODE_SEL           0x7
-#define CLK_MODE_MASK          0xfffffff8
-#define CLK_DIV_SEL            0xFFFFFFE0
 #define CPGMAC0_IDLE           0x30000
-#define DPLL_CLKDCOLDO_GATE_CTRL        0x300
-
 #define OSC    (V_OSCK/1000000)
 
-#define MPUPLL_M       CONFIG_SYS_MPUCLK
-#define MPUPLL_N       (OSC-1)
-#define MPUPLL_M2      1
-
-/* Core PLL Fdll = 1 GHZ, */
-#define COREPLL_M      1000
-#define COREPLL_N      (OSC-1)
-
-#define COREPLL_M4     10      /* CORE_CLKOUTM4 = 200 MHZ */
-#define COREPLL_M5     8       /* CORE_CLKOUTM5 = 250 MHZ */
-#define COREPLL_M6     4       /* CORE_CLKOUTM6 = 500 MHZ */
-
-/*
- * USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll
- * frequency needs to be set to 960 MHZ. Hence,
- * For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below
- */
-#define PERPLL_M       960
-#define PERPLL_N       (OSC-1)
-#define PERPLL_M2      5
-
-/* DDR Freq is 266 MHZ for now */
-/* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */
-#define DDRPLL_M       266
-#define DDRPLL_N       (OSC-1)
-#define DDRPLL_M2      1
-
 const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
 const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
 const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
 const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC;
 
+const struct dpll_regs dpll_mpu_regs = {
+       .cm_clkmode_dpll        = CM_WKUP + 0x88,
+       .cm_idlest_dpll         = CM_WKUP + 0x20,
+       .cm_clksel_dpll         = CM_WKUP + 0x2C,
+       .cm_div_m2_dpll         = CM_WKUP + 0xA8,
+};
+
+const struct dpll_regs dpll_core_regs = {
+       .cm_clkmode_dpll        = CM_WKUP + 0x90,
+       .cm_idlest_dpll         = CM_WKUP + 0x5C,
+       .cm_clksel_dpll         = CM_WKUP + 0x68,
+       .cm_div_m4_dpll         = CM_WKUP + 0x80,
+       .cm_div_m5_dpll         = CM_WKUP + 0x84,
+       .cm_div_m6_dpll         = CM_WKUP + 0xD8,
+};
+
+const struct dpll_regs dpll_per_regs = {
+       .cm_clkmode_dpll        = CM_WKUP + 0x8C,
+       .cm_idlest_dpll         = CM_WKUP + 0x70,
+       .cm_clksel_dpll         = CM_WKUP + 0x9C,
+       .cm_div_m2_dpll         = CM_WKUP + 0xAC,
+};
+
+const struct dpll_regs dpll_ddr_regs = {
+       .cm_clkmode_dpll        = CM_WKUP + 0x94,
+       .cm_idlest_dpll         = CM_WKUP + 0x34,
+       .cm_clksel_dpll         = CM_WKUP + 0x40,
+       .cm_div_m2_dpll         = CM_WKUP + 0xA0,
+};
+
+const struct dpll_params dpll_mpu = {
+               CONFIG_SYS_MPUCLK, OSC-1, 1, -1, -1, -1, -1};
+const struct dpll_params dpll_core = {
+               1000, OSC-1, -1, -1, 10, 8, 4};
+const struct dpll_params dpll_per = {
+               960, OSC-1, 5, -1, -1, -1, -1};
+
 static void enable_interface_clocks(void)
 {
        /* Enable all the Interconnect Modules */
@@ -238,142 +233,6 @@ static void enable_per_clocks(void)
                ;
 }
 
-void mpu_pll_config_val(int mpull_m)
-{
-       u32 clkmode, clksel, div_m2;
-
-       clkmode = readl(&cmwkup->clkmoddpllmpu);
-       clksel = readl(&cmwkup->clkseldpllmpu);
-       div_m2 = readl(&cmwkup->divm2dpllmpu);
-
-       /* Set the PLL to bypass Mode */
-       writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
-       while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
-               ;
-
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((mpull_m << CLK_SEL_SHIFT) | MPUPLL_N);
-       writel(clksel, &cmwkup->clkseldpllmpu);
-
-       div_m2 = div_m2 & ~CLK_DIV_MASK;
-       div_m2 = div_m2 | MPUPLL_M2;
-       writel(div_m2, &cmwkup->divm2dpllmpu);
-
-       clkmode = clkmode | CLK_MODE_SEL;
-       writel(clkmode, &cmwkup->clkmoddpllmpu);
-
-       while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
-               ;
-}
-
-static void mpu_pll_config(void)
-{
-       mpu_pll_config_val(CONFIG_SYS_MPUCLK);
-}
-
-static void core_pll_config(void)
-{
-       u32 clkmode, clksel, div_m4, div_m5, div_m6;
-
-       clkmode = readl(&cmwkup->clkmoddpllcore);
-       clksel = readl(&cmwkup->clkseldpllcore);
-       div_m4 = readl(&cmwkup->divm4dpllcore);
-       div_m5 = readl(&cmwkup->divm5dpllcore);
-       div_m6 = readl(&cmwkup->divm6dpllcore);
-
-       /* Set the PLL to bypass Mode */
-       writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
-
-       while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
-               ;
-
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
-       writel(clksel, &cmwkup->clkseldpllcore);
-
-       div_m4 = div_m4 & ~CLK_DIV_MASK;
-       div_m4 = div_m4 | COREPLL_M4;
-       writel(div_m4, &cmwkup->divm4dpllcore);
-
-       div_m5 = div_m5 & ~CLK_DIV_MASK;
-       div_m5 = div_m5 | COREPLL_M5;
-       writel(div_m5, &cmwkup->divm5dpllcore);
-
-       div_m6 = div_m6 & ~CLK_DIV_MASK;
-       div_m6 = div_m6 | COREPLL_M6;
-       writel(div_m6, &cmwkup->divm6dpllcore);
-
-       clkmode = clkmode | CLK_MODE_SEL;
-       writel(clkmode, &cmwkup->clkmoddpllcore);
-
-       while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
-               ;
-}
-
-static void per_pll_config(void)
-{
-       u32 clkmode, clksel, div_m2;
-
-       clkmode = readl(&cmwkup->clkmoddpllper);
-       clksel = readl(&cmwkup->clkseldpllper);
-       div_m2 = readl(&cmwkup->divm2dpllper);
-
-       /* Set the PLL to bypass Mode */
-       writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
-
-       while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
-               ;
-
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N);
-       writel(clksel, &cmwkup->clkseldpllper);
-
-       div_m2 = div_m2 & ~CLK_DIV2_MASK;
-       div_m2 = div_m2 | PERPLL_M2;
-       writel(div_m2, &cmwkup->divm2dpllper);
-
-       clkmode = clkmode | CLK_MODE_SEL;
-       writel(clkmode, &cmwkup->clkmoddpllper);
-
-       while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
-               ;
-
-       writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
-}
-
-void ddr_pll_config(unsigned int ddrpll_m)
-{
-       u32 clkmode, clksel, div_m2;
-
-       clkmode = readl(&cmwkup->clkmoddpllddr);
-       clksel = readl(&cmwkup->clkseldpllddr);
-       div_m2 = readl(&cmwkup->divm2dpllddr);
-
-       /* Set the PLL to bypass Mode */
-       clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE;
-       writel(clkmode, &cmwkup->clkmoddpllddr);
-
-       /* Wait till bypass mode is enabled */
-       while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS)
-                               != ST_MN_BYPASS)
-               ;
-
-       clksel = clksel & (~CLK_SEL_MASK);
-       clksel = clksel | ((ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N);
-       writel(clksel, &cmwkup->clkseldpllddr);
-
-       div_m2 = div_m2 & CLK_DIV_SEL;
-       div_m2 = div_m2 | DDRPLL_M2;
-       writel(div_m2, &cmwkup->divm2dpllddr);
-
-       clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL;
-       writel(clkmode, &cmwkup->clkmoddpllddr);
-
-       /* Wait till dpll is locked */
-       while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
-               ;
-}
-
 void enable_emif_clocks(void)
 {
        /* Enable the  EMIF_FW Functional clock */
@@ -390,10 +249,7 @@ void enable_emif_clocks(void)
  */
 void pll_init()
 {
-       mpu_pll_config();
-       core_pll_config();
-       per_pll_config();
-
+       setup_dplls();
        /* Enable the required interconnect clocks */
        enable_interface_clocks();
 
index 55dc321..15c4734 100644 (file)
@@ -79,6 +79,10 @@ static void config_vtp(int nr)
                ;
 }
 
+void __weak ddr_pll_config(unsigned int ddrpll_m)
+{
+}
+
 void config_ddr(unsigned int pll, unsigned int ioctrl,
                const struct ddr_data *data, const struct cmd_control *ctrl,
                const struct emif_regs *regs, int nr)
index 44c1e5d..703b80e 100644 (file)
 
 #include <asm/arch/clocks_am33xx.h>
 
+#define LDELAY 1000000
+
+/* CM_CLKMODE_DPLL */
+#define CM_CLKMODE_DPLL_REGM4XEN_SHIFT         11
+#define CM_CLKMODE_DPLL_REGM4XEN_MASK          (1 << 11)
+#define CM_CLKMODE_DPLL_LPMODE_EN_SHIFT                10
+#define CM_CLKMODE_DPLL_LPMODE_EN_MASK         (1 << 10)
+#define CM_CLKMODE_DPLL_RELOCK_RAMP_EN_SHIFT   9
+#define CM_CLKMODE_DPLL_RELOCK_RAMP_EN_MASK    (1 << 9)
+#define CM_CLKMODE_DPLL_DRIFTGUARD_EN_SHIFT    8
+#define CM_CLKMODE_DPLL_DRIFTGUARD_EN_MASK     (1 << 8)
+#define CM_CLKMODE_DPLL_RAMP_RATE_SHIFT                5
+#define CM_CLKMODE_DPLL_RAMP_RATE_MASK         (0x7 << 5)
+#define CM_CLKMODE_DPLL_EN_SHIFT               0
+#define CM_CLKMODE_DPLL_EN_MASK                        (0x7 << 0)
+
+#define CM_CLKMODE_DPLL_DPLL_EN_SHIFT          0
+#define CM_CLKMODE_DPLL_DPLL_EN_MASK           7
+
+#define DPLL_EN_STOP                   1
+#define DPLL_EN_MN_BYPASS              4
+#define DPLL_EN_LOW_POWER_BYPASS       5
+#define DPLL_EN_LOCK                   7
+
+/* CM_IDLEST_DPLL fields */
+#define ST_DPLL_CLK_MASK               1
+
+/* CM_CLKSEL_DPLL */
+#define CM_CLKSEL_DPLL_M_SHIFT                 8
+#define CM_CLKSEL_DPLL_M_MASK                  (0x7FF << 8)
+#define CM_CLKSEL_DPLL_N_SHIFT                 0
+#define CM_CLKSEL_DPLL_N_MASK                  0x7F
+
+struct dpll_params {
+       u32 m;
+       u32 n;
+       s8 m2;
+       s8 m3;
+       s8 m4;
+       s8 m5;
+       s8 m6;
+};
+
+struct dpll_regs {
+       u32 cm_clkmode_dpll;
+       u32 cm_idlest_dpll;
+       u32 cm_autoidle_dpll;
+       u32 cm_clksel_dpll;
+       u32 cm_div_m2_dpll;
+       u32 cm_div_m3_dpll;
+       u32 cm_div_m4_dpll;
+       u32 cm_div_m5_dpll;
+       u32 cm_div_m6_dpll;
+};
+
+extern const struct dpll_regs dpll_mpu_regs;
+extern const struct dpll_regs dpll_core_regs;
+extern const struct dpll_regs dpll_per_regs;
+extern const struct dpll_regs dpll_ddr_regs;
+extern const struct dpll_params dpll_mpu;
+extern const struct dpll_params dpll_core;
+extern const struct dpll_params dpll_per;
+extern const struct dpll_params dpll_ddr;
+
+extern const struct cm_wkuppll *cmwkup;
+
+void setup_dplls(void);
+const struct dpll_params *get_dpll_ddr_params(void);
+void do_setup_dpll(const struct dpll_regs *, const struct dpll_params *);
+
 #endif
index 18d7d99..683ba8e 100644 (file)
@@ -146,6 +146,8 @@ void set_sdram_timings(const struct emif_regs *regs, int nr);
  */
 void config_ddr_phy(const struct emif_regs *regs, int nr);
 
+void ddr_pll_config(unsigned int ddrpll_m);
+
 struct ddr_cmd_regs {
        unsigned int resv0[7];
        unsigned int cm0csratio;        /* offset 0x01C */
index 1424f90..dbcede0 100644 (file)
@@ -37,4 +37,5 @@ void omap_nand_switch_ecc(uint32_t, uint32_t);
 
 void rtc32k_enable(void);
 void uart_soft_reset(void);
+u32 wait_on_value(u32, u32, void *, u32);
 #endif
index c0f0c0d..034a8aa 100644 (file)
@@ -66,6 +66,16 @@ static struct emif_regs ddr3_emif_reg_data = {
        .zq_config = K4B2G1646EBIH9_ZQ_CFG,
        .emif_ddr_phy_ctlr_1 = K4B2G1646EBIH9_EMIF_READ_LATENCY,
 };
+
+#define OSC    (V_OSCK/1000000)
+const struct dpll_params dpll_ddr = {
+               303, OSC-1, 1, -1, -1, -1, -1};
+
+const struct dpll_params *get_dpll_ddr_params(void)
+{
+       return &dpll_ddr;
+}
+
 #endif
 
 /*
index 6291d03..17a98ff 100644 (file)
@@ -44,6 +44,15 @@ static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
 /* DDR RAM defines */
 #define DDR_CLK_MHZ            303 /* DDR_DPLL_MULT value */
 
+#define OSC    (V_OSCK/1000000)
+const struct dpll_params dpll_ddr = {
+               DDR_CLK_MHZ, OSC-1, 1, -1, -1, -1, -1};
+
+const struct dpll_params *get_dpll_ddr_params(void)
+{
+       return &dpll_ddr;
+}
+
 static const struct ddr_data ddr3_data = {
        .datardsratio0 = MT41J256M8HX15E_RD_DQS,
        .datawdsratio0 = MT41J256M8HX15E_WR_DQS,
index 728afc2..2be2297 100644 (file)
@@ -242,6 +242,33 @@ int spl_start_uboot(void)
 }
 #endif
 
+#define OSC    (V_OSCK/1000000)
+const struct dpll_params dpll_ddr = {
+               266, OSC-1, 1, -1, -1, -1, -1};
+const struct dpll_params dpll_ddr_evm_sk = {
+               303, OSC-1, 1, -1, -1, -1, -1};
+const struct dpll_params dpll_ddr_bone_black = {
+               400, OSC-1, 1, -1, -1, -1, -1};
+
+const struct dpll_params *get_dpll_ddr_params(void)
+{
+       struct am335x_baseboard_id header;
+
+       enable_i2c0_pin_mux();
+       i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+       if (read_eeprom(&header) < 0)
+               puts("Could not get board ID.\n");
+
+       if (board_is_evm_sk(&header))
+               return &dpll_ddr_evm_sk;
+       else if (board_is_bone_lt(&header))
+               return &dpll_ddr_bone_black;
+       else if (board_is_evm_15_or_later(&header))
+               return &dpll_ddr_evm_sk;
+       else
+               return &dpll_ddr;
+}
+
 #endif
 
 /*