int md_cd_power_on(struct ccci_modem *md) { int ret = 0; struct md_cd_ctrl *md_ctrl = (struct md_cd_ctrl *)md->private_data; #ifdef FEATURE_RF_CLK_BUF //config RFICx as BSI mutex_lock(&clk_buf_ctrl_lock); // fixme,clkbuf, ->down(&clk_buf_ctrl_lock_2); CCCI_INF_MSG(md->index, TAG, "clock buffer, BSI mode\n"); mt_set_gpio_mode(GPIO_RFIC0_BSI_CK, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_D0, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_D1, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_D2, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_CS, GPIO_MODE_01); #endif // power on MD_INFRA and MODEM_TOP switch(md->index) { case MD_SYS1: CCCI_INF_MSG(md->index, TAG, "Call start md_power_on()\n"); ret = md_power_on(SYS_MD1); CCCI_INF_MSG(md->index, TAG, "Call end md_power_on() ret=%d\n",ret); break; } #ifdef FEATURE_RF_CLK_BUF mutex_unlock(&clk_buf_ctrl_lock); // fixme,clkbuf, ->delete #endif if(ret) return ret; // disable MD WDT cldma_write32(md_ctrl->md_rgu_base, WDT_MD_MODE, WDT_MD_MODE_KEY); return 0; }
int md_ccif_power_on(struct ccci_modem *md) { int ret = 0; struct md_ccif_ctrl *md_ctrl = (struct md_ccif_ctrl *)md->private_data; switch (md->index) { case MD_SYS2: #if defined(CONFIG_MTK_LEGACY) CCCI_INF_MSG(md->index, TAG, "Call start md_power_on()\n"); ret = md_power_on(SYS_MD2); CCCI_INF_MSG(md->index, TAG, "Call end md_power_on() ret=%d\n", ret); #else CCCI_INF_MSG(md->index, TAG, "Call start clk_prepare_enable()\n"); clk_prepare_enable(clk_scp_sys_md2_main); CCCI_INF_MSG(md->index, TAG, "Call end clk_prepare_enable()\n"); #endif break; case MD_SYS3: #if defined(CONFIG_MTK_LEGACY) CCCI_INF_MSG(md->index, TAG, "Call start md_power_on()\n"); ret = md_power_on(SYS_MD2); CCCI_INF_MSG(md->index, TAG, "Call end md_power_on() ret=%d\n", ret); #else CCCI_INF_MSG(md->index, TAG, "Call start clk_prepare_enable()\n"); clk_prepare_enable(clk_scp_sys_md3_main); CCCI_INF_MSG(md->index, TAG, "Call end clk_prepare_enable()\n"); #endif break; } CCCI_INF_MSG(md->index, TAG, "md_ccif_power_on:ret=%d\n", ret); if (ret == 0 && md->index != MD_SYS3) { /*disable MD WDT */ ccif_write32(md_ctrl->md_rgu_base, WDT_MD_MODE, WDT_MD_MODE_KEY); } return ret; }
void c2k_modem_reset_platform(void) { int ret = 0; if (infra_ao_base == 0) c2k_hw_info_init(); c2k_write32(toprgu_base, TOP_RGU_WDT_SWSYSRST, (c2k_read32(toprgu_base, TOP_RGU_WDT_SWSYSRST) | 0x88000000) | (0x1 << 15)); #if defined(CONFIG_MTK_LEGACY) ret = md_power_on(SYS_MD2); #else ret = clk_prepare_enable(clk_scp_sys_md2_main); #endif pr_debug("[C2K] md_power_on %d\n", ret); /*step 1: reset C2K */ #if 0 pr_debug("[C2K] set toprgu wdt"); c2k_write32(toprgu_base, TOP_RGU_WDT_SWSYSRST, (c2k_read32(toprgu_base, TOP_RGU_WDT_SWSYSRST) | 0x88000000) & (~(0x1 << 15))); #else mtk_wdt_set_c2k_sysrst(1); #endif pr_debug("[C2K] TOP_RGU_WDT_SWSYSRST = 0x%x\n", c2k_read32(toprgu_base, TOP_RGU_WDT_SWSYSRST)); /*step 2: wake up C2K */ c2k_write32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL, c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL) | 0x1); while (!((c2k_read32(infra_ao_base, INFRA_AO_C2K_STATUS) >> 1) & 0x1)) ; c2k_write32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL, c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL) & (~0x1)); pr_debug("[C2K] C2K_SPM_CTRL = 0x%x\n", c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL)); #if 0 while (c2k_read32(c2k_chip_id_base, 0) != 0x020AC000) { pr_debug("[C2K] C2K_CHIP_ID = 0x%x\n", c2k_read32(c2k_chip_id_base, 0)); } pr_debug("[C2K] C2K_CHIP_ID = 0x%x\n", c2k_read32(c2k_chip_id_base, 0)); #endif }
static void internal_md2_power_down(void) { int ret = 0; unsigned short status, i; void __iomem *md_topsm_base, *modem_lite_topsm_base, *modem_topsm_base; pr_debug("[ccci-off]shutdown MDSYS2 !!!\n"); ret = md_power_on(SYS_MD2); if (ret) return; md_topsm_base = ioremap_nocache(MD2_TOPSM_BASE, 0x8C0); modem_lite_topsm_base = ioremap_nocache(MODEM2_LITE_TOPSM_BASE, 0x08C0); modem_topsm_base = ioremap_nocache(MODEM2_TOPSM_BASE, 0x8C0); pr_debug("[ccci-off]9.power on MD-2G/HSPA\n"); /* power on MD2G */ sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)) | 0x44, MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)); pr_debug("[ccci-off]10.power off MD-2G/HSPA\n"); /* power off MD2G */ sync_write32(0xFFFFFFFF, MD_TOPSM_SM_REQ_MASK(md_topsm_base)); sync_write32(0, MODEM_LITE_TOPSM_RM_TMR_PWR0(modem_lite_topsm_base)); sync_write32(0, MODEM_LITE_TOPSM_RM_TMR_PWR1(modem_lite_topsm_base)); sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)); pr_debug("[ccci-off]11.power off ABB\n"); /* power off ABB */ sync_write32(ioread32(MD_TOPSM_RM_PWR_CON1(md_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MD_TOPSM_RM_PWR_CON1(md_topsm_base)); sync_write32(ioread32(MD_TOPSM_RM_PWR_CON1(md_topsm_base)) | 0x00000090, MD_TOPSM_RM_PWR_CON1(md_topsm_base)); sync_write32(ioread32(MD_TOPSM_RM_PLL_MASK0(md_topsm_base)) | 0xFFFF0000, MD_TOPSM_RM_PLL_MASK0(md_topsm_base)); sync_write32(ioread32(MD_TOPSM_RM_PLL_MASK1(md_topsm_base)) | 0xFFFFFFFF, MD_TOPSM_RM_PLL_MASK1(md_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PLL_MASK0(modem_topsm_base)) | 0xFFFFFFFF, MODEM_TOPSM_RM_PLL_MASK0(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PLL_MASK1(modem_topsm_base)) | 0x0000000F, MODEM_TOPSM_RM_PLL_MASK1(modem_topsm_base)); sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PLL_MASK0(modem_lite_topsm_base)) | 0xFFFFFFFF, MODEM_LITE_TOPSM_RM_PLL_MASK0(modem_lite_topsm_base)); sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PLL_MASK1(modem_lite_topsm_base)) | 0x0000000F, MODEM_LITE_TOPSM_RM_PLL_MASK1(modem_lite_topsm_base)); pr_debug("[ccci-off]12.power off MD_INFRA/MODEM_TOP\n"); /* no need to poll, as MD SW didn't run and enter sleep mode, polling will not get result */ md_power_off(SYS_MD2, 0); }
int md_ccif_power_on(struct ccci_modem *md) { int ret = 0; struct md_ccif_ctrl *md_ctrl = (struct md_ccif_ctrl *)md->private_data; switch(md->index) { case MD_SYS2: ret = md_power_on(SYS_MD2); break; } CCCI_INF_MSG(md->index, TAG, "md_ccif_power_on:ret=%d\n",ret); if(ret==0){ // disable MD WDT ccif_write32(md_ctrl->md_rgu_base, WDT_MD_MODE, WDT_MD_MODE_KEY); } return ret; }
static void internal_md_power_down(void) { /** * MDMCU Control Power Registers */ #define MD_TOPSM_BASE (0x20030000) #define MD_TOPSM_RM_TMR_PWR0(base) ((volatile unsigned int*)((base) + 0x0018)) #define MD_TOPSM_SM_REQ_MASK(base) ((volatile unsigned int*)((base) + 0x08B0)) #define MD_TOPSM_RM_PWR_CON0(base) ((volatile unsigned int*)((base) + 0x0800)) #define MD_TOPSM_RM_PWR_CON1(base) ((volatile unsigned int*)((base) + 0x0804)) #define MD_TOPSM_RM_PLL_MASK0(base) ((volatile unsigned int*)((base) + 0x0830)) #define MD_TOPSM_RM_PLL_MASK1(base) ((volatile unsigned int*)((base) + 0x0834)) #define MODEM2G_TOPSM_BASE (0x23010000) #define MODEM2G_TOPSM_RM_CLK_SETTLE(base) ((volatile unsigned int*)((base) + 0x0000)) #define MODEM2G_TOPSM_RM_TMRPWR_SETTLE(base) ((volatile unsigned int*)((base) + 0x0004)) #define MODEM2G_TOPSM_RM_TMR_TRG0(base) ((volatile unsigned int*)((base) + 0x0010)) #define MODEM2G_TOPSM_RM_TMR_TRG1(base) ((volatile unsigned int*)((base) + 0x0014)) #define MODEM2G_TOPSM_RM_TMR_PWR0(base) ((volatile unsigned int*)((base) + 0x0018)) #define MODEM2G_TOPSM_RM_TMR_PWR1(base) ((volatile unsigned int*)((base) + 0x001C)) #define MODEM2G_TOPSM_RM_PWR_CON0(base) ((volatile unsigned int*)((base) + 0x0800)) #define MODEM2G_TOPSM_RM_PWR_CON1(base) ((volatile unsigned int*)((base) + 0x0804)) #define MODEM2G_TOPSM_RM_PWR_CON2(base) ((volatile unsigned int*)((base) + 0x0808)) #define MODEM2G_TOPSM_RM_PWR_CON3(base) ((volatile unsigned int*)((base) + 0x080C)) #define MODEM2G_TOPSM_RM_PWR_CON4(base) ((volatile unsigned int*)((base) + 0x0810)) #define MODEM2G_TOPSM_RM_PWR_CON5(base) ((volatile unsigned int*)((base) + 0x0814)) #define MODEM2G_TOPSM_RM_PWR_CON6(base) ((volatile unsigned int*)((base) + 0x0818)) #define MODEM2G_TOPSM_RM_PWR_CON7(base) ((volatile unsigned int*)((base) + 0x081C)) #define MODEM2G_TOPSM_RM_PLL_MASK0(base) ((volatile unsigned int*)((base) + 0x0830)) #define MODEM2G_TOPSM_RM_PLL_MASK1(base) ((volatile unsigned int*)((base) + 0x0834)) #define MODEM2G_TOPSM_RM_PLL_MASK2(base) ((volatile unsigned int*)((base) + 0x0838)) #define MODEM2G_TOPSM_RM_PLL_MASK3(base) ((volatile unsigned int*)((base) + 0x083C)) #define MODEM2G_TOPSM_SM_REQ_MASK(base) ((volatile unsigned int*)((base) + 0x08B0)) /** *[TDD] MDMCU Control Power Registers */ #define TDD_BASE (0x24000000) #define TDD_HALT_CFG_ADDR(base) ((volatile unsigned int*)((base) + 0x0000)) #define TDD_HALT_STATUS_ADDR(base) ((volatile unsigned int*)((base) + 0x0002)) unsigned short status; unsigned short i; unsigned int md_topsm_base, modem2g_topsm_base, tdd_base; printk("[ccci/ctl] (0)internal md disabled, so power down!\n"); //printk("[ccci/ctl] (0)call md_power_on...\n"); md_power_on(0); md_topsm_base = (unsigned int)ioremap_nocache(MD_TOPSM_BASE, 0x840); modem2g_topsm_base = (unsigned int)ioremap_nocache(MODEM2G_TOPSM_BASE, 0x8C0); tdd_base = (unsigned int)ioremap_nocache(TDD_BASE, 0x010); //printk("[ccci/ctl] (0)MD2G/HSPA power down...\n"); /*[MD2G/HSPA] MDMCU Control Power Down Sequence*/ mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)) | 0x44, MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)) | 0x44, MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)) | 0x44, MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)) | 0x44, MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)) | 0x44, MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)) & 0xFFFFFF7F, MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)); mt65xx_reg_sync_writel(0x00000200, MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)) & 0xFFFFFF7F, MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)); mt65xx_reg_sync_writel(0x00000200, MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)) & 0xFFFFFF7F, MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)); mt65xx_reg_sync_writel(0x00000200, MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)) & 0xFFFFFF7F, MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)); mt65xx_reg_sync_writel(0x00000200, MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)) & 0xFFFFFF7F, MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)); mt65xx_reg_sync_writel(0x00000200, MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)); mt65xx_reg_sync_writel(0xFFFFFFFF, MD_TOPSM_SM_REQ_MASK(md_topsm_base)); mt65xx_reg_sync_writel(0x00000000, MODEM2G_TOPSM_RM_TMR_PWR0(modem2g_topsm_base)); mt65xx_reg_sync_writel(0x00000000, MODEM2G_TOPSM_RM_TMR_PWR1(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)) & ~(0x1<<2) & ~(0x1<<6), MODEM2G_TOPSM_RM_PWR_CON0(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)) & ~(0x1<<2) & ~(0x1<<6), MODEM2G_TOPSM_RM_PWR_CON1(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)) & ~(0x1<<2) & ~(0x1<<6), MODEM2G_TOPSM_RM_PWR_CON2(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)) & ~(0x1<<2) & ~(0x1<<6), MODEM2G_TOPSM_RM_PWR_CON3(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)) & ~(0x1<<2) & ~(0x1<<6), MODEM2G_TOPSM_RM_PWR_CON4(modem2g_topsm_base)); //printk("[ccci/ctl] (0)TDD power down...\n"); /*[TDD] MDMCU Control Power Down Sequence*/ mt65xx_reg_sync_writew(0x1, TDD_HALT_CFG_ADDR(tdd_base)); status = *((volatile unsigned short*)TDD_HALT_CFG_ADDR(tdd_base)); while ((status & 0x1) == 0) { if (status & 0x1) { //halted /*TINFO=''TDD is in *HALT* STATE*/ } else if (status & 0x2) { //normal /*TINFO=''TDD is in *NORMAL* STATE*/ } else if (status & 0x4) { //sleep /*TINFO=''TDD is in *SLEEP* STATE*/ } i = 100; while(i--); status = *((volatile unsigned short*)TDD_HALT_CFG_ADDR(tdd_base)); } //printk("[ccci/ctl] (0)ABB power down...\n"); /*[ABB] MDMCU Control Power Down Sequence*/ mt65xx_reg_sync_writel((*MD_TOPSM_RM_PWR_CON0(md_topsm_base)) | 0x00000090, MD_TOPSM_RM_PWR_CON0(md_topsm_base)); mt65xx_reg_sync_writel((*MD_TOPSM_RM_PLL_MASK0(md_topsm_base)) | 0xFFFF0000, MD_TOPSM_RM_PLL_MASK0(md_topsm_base)); mt65xx_reg_sync_writel((*MD_TOPSM_RM_PLL_MASK1(md_topsm_base)) | 0x000000FF, MD_TOPSM_RM_PLL_MASK1(md_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PLL_MASK0(modem2g_topsm_base)) | 0xFFFFFFFF, MODEM2G_TOPSM_RM_PLL_MASK0(modem2g_topsm_base)); mt65xx_reg_sync_writel((*MODEM2G_TOPSM_RM_PLL_MASK1(modem2g_topsm_base)) | 0x0000000F, MODEM2G_TOPSM_RM_PLL_MASK1(modem2g_topsm_base)); //printk("[ccci/ctl] (0)MDMCU power down...\n"); /*[MDMCU] APMCU Control Power Down Sequence*/ mt65xx_reg_sync_writel(0xFFFFFFFF, MD_TOPSM_SM_REQ_MASK(md_topsm_base)); mt65xx_reg_sync_writel(0x00000000, MD_TOPSM_RM_TMR_PWR0(md_topsm_base)); mt65xx_reg_sync_writel(0x0005229A, MD_TOPSM_RM_PWR_CON0(md_topsm_base)); mt65xx_reg_sync_writel(0xFFFFFFFF, MD_TOPSM_RM_PLL_MASK0(md_topsm_base)); mt65xx_reg_sync_writel(0xFFFFFFFF, MD_TOPSM_RM_PLL_MASK1(md_topsm_base)); mt65xx_reg_sync_writel(0xFFFFFFFF, MODEM2G_TOPSM_SM_REQ_MASK(modem2g_topsm_base)); mt65xx_reg_sync_writel(0xFFFFFFFF, MODEM2G_TOPSM_RM_PLL_MASK0(modem2g_topsm_base)); mt65xx_reg_sync_writel(0xFFFFFFFF, MODEM2G_TOPSM_RM_PLL_MASK1(modem2g_topsm_base)); //printk("[ccci/ctl] (0)call md_power_off...\n"); md_power_off(0, 100); iounmap((void*)md_topsm_base); iounmap((void*)modem2g_topsm_base); iounmap((void*)tdd_base); }
void c2k_modem_power_on_platform(void) { int ret; #if ENABLE_C2K_JTAG /*ARM legacy JTAG for C2K*/ md_gpio_set(0x80000000 | GPIO82, GPIO_MODE_05, GPIO_DIR_IN, GPIO_OUT_UNSUPPORTED, GPIO_PULL_ENABLE, GPIO_PULL_DOWN, GPIO_SMT_ENABLE); md_gpio_set(0x80000000 | GPIO81, GPIO_MODE_05, GPIO_DIR_IN, GPIO_OUT_UNSUPPORTED, GPIO_PULL_ENABLE, GPIO_PULL_UP, GPIO_SMT_ENABLE); md_gpio_set(0x80000000 | GPIO83, GPIO_MODE_05, GPIO_DIR_IN, GPIO_OUT_UNSUPPORTED, GPIO_PULL_ENABLE, GPIO_PULL_UP, GPIO_SMT_DISABLE); md_gpio_set(0x80000000 | GPIO85, GPIO_MODE_05, GPIO_DIR_IN, GPIO_OUT_UNSUPPORTED, GPIO_PULL_ENABLE, GPIO_PULL_UP, GPIO_SMT_DISABLE); md_gpio_set(0x80000000 | GPIO84, GPIO_MODE_05, GPIO_DIR_OUT, GPIO_OUT_ZERO, GPIO_PULL_EN_UNSUPPORTED, GPIO_PULL_UNSUPPORTED, GPIO_SMT_UNSUPPORTED); md_gpio_set(0x80000000 | GPIO86, GPIO_MODE_05, GPIO_DIR_OUT, GPIO_OUT_ZERO, GPIO_PULL_EN_UNSUPPORTED, GPIO_PULL_UNSUPPORTED, GPIO_SMT_UNSUPPORTED); #endif pr_debug("[C2K] c2k_modem_power_on enter\n"); if (infra_ao_base == 0) c2k_hw_info_init(); pr_debug("[C2K] prepare to power on c2k\n"); /*step 0: power on MTCMOS */ #if defined(CONFIG_MTK_LEGACY) ret = md_power_on(SYS_MD2); #else ret = clk_prepare_enable(clk_scp_sys_md2_main); #endif pr_debug("[C2K] md_power_on %d\n", ret); /*step 1: set C2K boot mode */ c2k_write32(infra_ao_base, INFRA_AO_C2K_CONFIG, (c2k_read32(infra_ao_base, INFRA_AO_C2K_CONFIG) & (~(0x7 << 8)))); pr_debug("[C2K] C2K_CONFIG = 0x%x\n", c2k_read32(infra_ao_base, INFRA_AO_C2K_CONFIG)); /*step 2: config srcclkena selection mask */ c2k_write32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL, c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL) & (~(0xF << 2))); c2k_write32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL, c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL) | (0x9 << 2)); pr_debug("[C2K] C2K_SPM_CTRL = 0x%x\n", c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL)); c2k_write32(sleep_base, SLEEP_CLK_CON, c2k_read32(sleep_base, SLEEP_CLK_CON) | 0xc); c2k_write32(sleep_base, SLEEP_CLK_CON, c2k_read32(sleep_base, SLEEP_CLK_CON) & (~(0x1 << 14))); c2k_write32(sleep_base, SLEEP_CLK_CON, c2k_read32(sleep_base, SLEEP_CLK_CON) | (0x1 << 12)); c2k_write32(sleep_base, SLEEP_CLK_CON, c2k_read32(sleep_base, SLEEP_CLK_CON) | (0x1 << 27)); pr_debug("[C2K] SLEEP_CLK_CON = 0x%x\n", c2k_read32(sleep_base, SLEEP_CLK_CON)); /*step 3: PMIC VTCXO_1 enable */ pmic_config_interface(0x0A02, 0xA12E, 0xFFFF, 0x0); /*step 4: reset C2K */ #if 0 c2k_write32(toprgu_base, TOP_RGU_WDT_SWSYSRST, (c2k_read32(toprgu_base, TOP_RGU_WDT_SWSYSRST) | 0x88000000) & (~(0x1 << 15))); #else mtk_wdt_set_c2k_sysrst(1); #endif pr_debug("[C2K] TOP_RGU_WDT_SWSYSRST = 0x%x\n", c2k_read32(toprgu_base, TOP_RGU_WDT_SWSYSRST)); /*step 5: set memory remap */ if (first_init) { first_init = 0; c2k_write32(infra_ao_base, MD3_BANK0_MAP0, ((((unsigned int)md3_mem_base - 0x40000000) >> 24) | 0x1) & 0xFF); #if ENABLE_C2K_EMI_PROTECTION set_c2k_mpu(); #endif pr_debug("[C2K] MD3_BANK0_MAP0 = 0x%x\n", c2k_read32(infra_ao_base, MD3_BANK0_MAP0)); } /*step 6: wake up C2K */ c2k_write32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL, c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL) | 0x1); while (!((c2k_read32(infra_ao_base, INFRA_AO_C2K_STATUS) >> 1) & 0x1)) ; pr_debug("[C2K] C2K_STATUS = 0x%x\n", c2k_read32(infra_ao_base, INFRA_AO_C2K_STATUS)); c2k_write32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL, c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL) & (~0x1)); pr_debug("[C2K] C2K_SPM_CTRL = 0x%x, C2K_STATUS = 0x%x\n", c2k_read32(infra_ao_base, INFRA_AO_C2K_SPM_CTRL), c2k_read32(infra_ao_base, INFRA_AO_C2K_STATUS)); #if 0 while (c2k_read32(c2k_chip_id_base, 0) != 0x020AC000) { pr_debug("[C2K] C2K_CHIP_ID = 0x%x\n", c2k_read32(c2k_chip_id_base, 0)); } pr_debug("[C2K] C2K_CHIP_ID = 0x%x!!\n", c2k_read32(c2k_chip_id_base, 0)); #endif }
int md_cd_power_on(struct ccci_modem *md) { int ret = 0; unsigned int reg_value; struct md_cd_ctrl *md_ctrl = (struct md_cd_ctrl *)md->private_data; // turn on VLTE #ifdef FEATURE_VLTE_SUPPORT mt_set_gpio_out(GPIO_LTE_VSRAM_EXT_POWER_EN_PIN,1); CCCI_INF_MSG(md->index, CORE, "md_cd_power_on:mt_set_gpio_out(GPIO_LTE_VSRAM_EXT_POWER_EN_PIN,1)\n"); //if(!(mt6325_upmu_get_swcid()==PMIC6325_E1_CID_CODE || // mt6325_upmu_get_swcid()==PMIC6325_E2_CID_CODE)) { CCCI_INF_MSG(md->index, CORE, "md_cd_power_on:set VLTE on,bit0,1\n"); pmic_config_interface(0x04D6, 0x1, 0x1, 0); //bit[0] =>1'b1 udelay(200); /* *[Notes] move into md cmos flow, for hardwareissue, so disable on denlai. * bring up need confirm with MD DE & SPM */ //reg_value = ccci_read32(infra_ao_base,0x338); //reg_value &= ~(0x40); //bit[6] =>1'b0 //ccci_write32(infra_ao_base,0x338,reg_value); //CCCI_INF_MSG(md->index, CORE, "md_cd_power_on: set infra_misc VLTE bit(0x1000_0338)=0x%x, bit[6]=0x%x\n",ccci_read32(infra_ao_base,0x338),(ccci_read32(infra_ao_base,0x338)&0x40)); } #endif #ifdef FEATURE_RF_CLK_BUF //config RFICx as BSI mutex_lock(&clk_buf_ctrl_lock); // fixme,clkbuf, ->down(&clk_buf_ctrl_lock_2); CCCI_INF_MSG(md->index, TAG, "clock buffer, BSI ignore mode\n"); mt_set_gpio_mode(GPIO_RFIC0_BSI_CK, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_D0, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_D1, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_D2, GPIO_MODE_01); mt_set_gpio_mode(GPIO_RFIC0_BSI_CS, GPIO_MODE_01); #endif // power on MD_INFRA and MODEM_TOP switch(md->index) { case MD_SYS1: #if defined(CONFIG_MTK_LEGACY) CCCI_INF_MSG(md->index, TAG, "Call start md_power_on()\n"); ret = md_power_on(SYS_MD1); CCCI_INF_MSG(md->index, TAG, "Call end md_power_on() ret=%d\n",ret); #else CCCI_INF_MSG(md->index, TAG, "Call start clk_prepare_enable()\n"); clk_prepare_enable(clk_scp_sys_md1_main); CCCI_INF_MSG(md->index, TAG, "Call end clk_prepare_enable()\n"); #endif kicker_pbm_by_md(MD1,true); CCCI_INF_MSG(md->index, TAG, "Call end kicker_pbm_by_md(0,true)\n"); break; } #ifdef FEATURE_RF_CLK_BUF mutex_unlock(&clk_buf_ctrl_lock); // fixme,clkbuf, ->delete #endif if(ret) return ret; // disable MD WDT cldma_write32(md_ctrl->md_rgu_base, WDT_MD_MODE, WDT_MD_MODE_KEY); return 0; }
static void internal_md_power_down(void) { int ret = 0; unsigned short status; unsigned short i; void __iomem *md_topsm_base, *modem_lite_topsm_base, *modem_topsm_base, *tdd_base, *ltelt1_base, *ltelt1_base_1, *ltelt1_base_2, *md_pll_mixedsys_base; /* Mask this power on function */ #if 0 pr_debug("[ccci-off]shutdown MDSYS1 !!!\n"); ret = md_power_on(SYS_MD1); pr_debug("[ccci-off]0.power on MD_INFRA/MODEM_TOP ret=%d\n", ret); if (ret) return; #endif md_topsm_base = ioremap_nocache(MD_TOPSM_BASE, 0x8C0); modem_lite_topsm_base = ioremap_nocache(MODEM_LITE_TOPSM_BASE, 0x08C0); modem_topsm_base = ioremap_nocache(MODEM_TOPSM_BASE, 0x8C0); tdd_base = ioremap_nocache(TDD_BASE, 0x010); ltelt1_base = ioremap_nocache(LTEL1_BASE, 0x60000); ltelt1_base_1 = ioremap_nocache(0x2012045C, 0x4); ltelt1_base_2 = ioremap_nocache(0x200308B0, 0x4); md_pll_mixedsys_base = ioremap_nocache(MD_PLL_MIXEDSYS_BASE, 0x160); pr_debug("[ccci-off]1.power on MD2G/HSPA\n"); /* power on MD2G */ sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)) | 0x44, MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)); /* power on MD2G SRAM */ #if 0 sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)) | 0x88, MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)); #endif /* power on HSPA */ sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON1(modem_topsm_base)) | 0x44, MODEM_TOPSM_RM_PWR_CON1(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON2(modem_topsm_base)) | 0x44, MODEM_TOPSM_RM_PWR_CON2(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON3(modem_topsm_base)) | 0x44, MODEM_TOPSM_RM_PWR_CON3(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON4(modem_topsm_base)) | 0x44, MODEM_TOPSM_RM_PWR_CON4(modem_topsm_base)); /* power on HSPA SRAM */ #if 0 sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON1(modem_topsm_base)) | 0x88, MODEM_TOPSM_RM_PWR_CON1(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON2(modem_topsm_base)) | 0x88, MODEM_TOPSM_RM_PWR_CON2(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON3(modem_topsm_base)) | 0x88, MODEM_TOPSM_RM_PWR_CON3(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON4(modem_topsm_base)) | 0x88, MODEM_TOPSM_RM_PWR_CON4(modem_topsm_base)); #endif pr_debug("[ccci-off]2.power off MD2G/HSPA\n"); /* power off MD2G */ sync_write32(0xFFFFFFFF, MD_TOPSM_SM_REQ_MASK(md_topsm_base)); sync_write32(0, MODEM_LITE_TOPSM_RM_TMR_PWR0(modem_lite_topsm_base)); sync_write32(0, MODEM_LITE_TOPSM_RM_TMR_PWR1(modem_lite_topsm_base)); sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MODEM_LITE_TOPSM_RM_PWR_CON0(modem_lite_topsm_base)); /* power off HSPA */ sync_write32(0xFFFFFFFF, MD_TOPSM_SM_REQ_MASK(md_topsm_base)); sync_write32(0, MODEM_TOPSM_RM_TMR_PWR0(modem_topsm_base)); sync_write32(0, MODEM_TOPSM_RM_TMR_PWR1(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON1(modem_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MODEM_TOPSM_RM_PWR_CON1(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON2(modem_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MODEM_TOPSM_RM_PWR_CON2(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON3(modem_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MODEM_TOPSM_RM_PWR_CON3(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PWR_CON4(modem_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MODEM_TOPSM_RM_PWR_CON4(modem_topsm_base)); pr_debug("[ccci-off]3.power off TDD\n"); sync_write16(0x1, TDD_HALT_CFG_ADDR(tdd_base)); status = ioread16(TDD_HALT_STATUS_ADDR(tdd_base)); while ((status & 0x1) == 0) { /* * status & 0x1 TDD is in *HALT* STATE * status & 0x2 TDD is in *NORMAL* STATE * status & 0x4 TDD is in *SLEEP* STATE */ i = 100; while (i--) ; status = ioread16(TDD_HALT_STATUS_ADDR(tdd_base)); } pr_debug("[ccci-off]4.power off LTEL1\n"); sync_write32(0x01FF, PLL_DFS_CON7(md_pll_mixedsys_base)); sync_write32(0x0010, PLL_PLL_CON4(md_pll_mixedsys_base)); sync_write32(0x6000, PLL_ARM7PLL_CON1(md_pll_mixedsys_base)); sync_write32(0x2000, PLL_ARM7PLL_CON1(md_pll_mixedsys_base)); sync_write32(ioread32(PLL_ARM7PLL_CON0(md_pll_mixedsys_base)) | 0x8000, PLL_ARM7PLL_CON0(md_pll_mixedsys_base)); sync_write32(ioread32(PLL_MDPLL_CON0(md_pll_mixedsys_base)) | 0x8000, PLL_MDPLL_CON0(md_pll_mixedsys_base)); sync_write32(0x4500, PLL_CLKSW_CKSEL4(md_pll_mixedsys_base)); sync_write32(0x0003, PLL_CLKSW_CKSEL6(md_pll_mixedsys_base)); sync_write32(0x21008510, ltelt1_base_1); sync_write32(ioread32(ltelt1_base_2) | 0xC, ltelt1_base_2); sync_write32(0x01010101, ltelt1_base + 0x030c8); sync_write32(0x10041000, ltelt1_base + 0x0306c); sync_write32(0x10041000, ltelt1_base + 0x03070); sync_write32(0x10041000, ltelt1_base + 0x03074); sync_write32(0x10040000, ltelt1_base + 0x0306c); sync_write32(0x10040000, ltelt1_base + 0x03070); sync_write32(0x10040000, ltelt1_base + 0x03074); sync_write32(0x10040000, ltelt1_base + 0x03078); sync_write32(0x88888888, ltelt1_base + 0x02000); sync_write32(0x88888888, ltelt1_base + 0x02004); sync_write32(0x88888888, ltelt1_base + 0x02008); sync_write32(0x88888888, ltelt1_base + 0x0200c); sync_write32(0x88888888, ltelt1_base + 0x32000); sync_write32(0x88888888, ltelt1_base + 0x32004); sync_write32(0x88888888, ltelt1_base + 0x22000); sync_write32(0x88888888, ltelt1_base + 0x22004); sync_write32(0x88888888, ltelt1_base + 0x22008); sync_write32(0x88888888, ltelt1_base + 0x2200c); sync_write32(0x88888888, ltelt1_base + 0x22010); sync_write32(0x88888888, ltelt1_base + 0x22014); sync_write32(0x88888888, ltelt1_base + 0x22018); sync_write32(0x88888888, ltelt1_base + 0x2201c); sync_write32(0x88888888, ltelt1_base + 0x42000); sync_write32(0x88888888, ltelt1_base + 0x42004); sync_write32(0x88888888, ltelt1_base + 0x42008); sync_write32(0x88888888, ltelt1_base + 0x52000); sync_write32(0x88888888, ltelt1_base + 0x52004); sync_write32(0x88888888, ltelt1_base + 0x52008); sync_write32(0x88888888, ltelt1_base + 0x5200c); sync_write32(0x88888888, ltelt1_base + 0x12000); sync_write32(0x88888888, ltelt1_base + 0x12004); sync_write32(0x88888888, ltelt1_base + 0x12008); sync_write32(0x88888888, ltelt1_base + 0x1200c); sync_write32(0x0000000C, ltelt1_base + 0x031b4); sync_write32(0x00520C41, ltelt1_base + 0x031c4); sync_write32(0x00000004, ltelt1_base + 0x02030); sync_write32(0x00000008, ltelt1_base + 0x02034); sync_write32(0x0000000C, ltelt1_base + 0x02038); sync_write32(0x00000010, ltelt1_base + 0x0203c); sync_write32(0x00000018, ltelt1_base + 0x02040); sync_write32(0x00000004, ltelt1_base + 0x32028); sync_write32(0x00000008, ltelt1_base + 0x3202c); sync_write32(0x0000000C, ltelt1_base + 0x32030); sync_write32(0x00000010, ltelt1_base + 0x32034); sync_write32(0x00000018, ltelt1_base + 0x32038); sync_write32(0x00080004, ltelt1_base + 0x22044); sync_write32(0x00100008, ltelt1_base + 0x22048); sync_write32(0x0000000C, ltelt1_base + 0x2204c); sync_write32(0x00000010, ltelt1_base + 0x22050); sync_write32(0x00000018, ltelt1_base + 0x22054); sync_write32(0x00000004, ltelt1_base + 0x4202c); sync_write32(0x00000008, ltelt1_base + 0x42030); sync_write32(0x0000000C, ltelt1_base + 0x42034); sync_write32(0x00000010, ltelt1_base + 0x42038); sync_write32(0x00000018, ltelt1_base + 0x4203c); sync_write32(0x00000004, ltelt1_base + 0x5202c); sync_write32(0x00000008, ltelt1_base + 0x52030); sync_write32(0x0000000C, ltelt1_base + 0x52034); sync_write32(0x00000010, ltelt1_base + 0x52038); sync_write32(0x00000018, ltelt1_base + 0x5203c); sync_write32(0x00000004, ltelt1_base + 0x1202c); sync_write32(0x00000008, ltelt1_base + 0x12030); sync_write32(0x0000000C, ltelt1_base + 0x12034); sync_write32(0x00000010, ltelt1_base + 0x12038); sync_write32(0x00000018, ltelt1_base + 0x1203c); sync_write32(0x05004321, ltelt1_base + 0x030a0); sync_write32(0x00432064, ltelt1_base + 0x030a4); sync_write32(0x0000000F, ltelt1_base + 0x03118); sync_write32(0x00000000, ltelt1_base + 0x03104); sync_write32(0x00000000, ltelt1_base + 0x03100); sync_write32(0x02020006, ltelt1_base + 0x03004); sync_write32(0x00000002, ltelt1_base + 0x03110); sync_write32(0x00000001, ltelt1_base + 0x030f0); sync_write32(ioread32(ltelt1_base + 0x030d4) | 0x1, ltelt1_base + 0x030d4); sync_write32(0x01010101, ltelt1_base + 0x030b8); sync_write32(0x01010101, ltelt1_base + 0x030bc); sync_write32(0x00000000, ltelt1_base + 0x04014); sync_write32(0x00000190, ltelt1_base + 0x04018); sync_write32(0x000000C8, ltelt1_base + 0x0401c); sync_write32(0x0000001E, ltelt1_base + 0x04028); sync_write32(0x00000001, ltelt1_base + 0x030d4); udelay(1000); sync_write32(0x00000030, ltelt1_base + 0x04058); udelay(1000); sync_write32(0x00000001, ltelt1_base + 0x03120); udelay(1000); sync_write32(0x00000001, ltelt1_base + 0x04000); udelay(1000); sync_write32(ioread32(PLL_ARM7PLL_CON0(md_pll_mixedsys_base)) & ~(0x8000), PLL_ARM7PLL_CON0(md_pll_mixedsys_base)); sync_write32(ioread32(PLL_MDPLL_CON0(md_pll_mixedsys_base)) & ~(0x8000), PLL_MDPLL_CON0(md_pll_mixedsys_base)); sync_write32(0x6000, PLL_ARM7PLL_CON1(md_pll_mixedsys_base)); sync_write32(0x4000, PLL_ARM7PLL_CON1(md_pll_mixedsys_base)); pr_debug("[ccci-off]5.power off LTEL2/ARM7\n"); /* power off LTEL2 */ sync_write32(ioread32(MD_TOPSM_RM_PWR_CON2(md_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MD_TOPSM_RM_PWR_CON2(md_topsm_base)); /* power off ARM7 */ sync_write32(ioread32(MD_TOPSM_RM_PWR_CON3(md_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MD_TOPSM_RM_PWR_CON3(md_topsm_base)); pr_debug("[ccci-off]6.power off ABB\n"); sync_write32(ioread32(MD_TOPSM_RM_PWR_CON1(md_topsm_base)) & ~(0x1 << 2) & ~(0x1 << 6), MD_TOPSM_RM_PWR_CON1(md_topsm_base)); sync_write32(ioread32(MD_TOPSM_RM_PWR_CON1(md_topsm_base)) | 0x00000090, MD_TOPSM_RM_PWR_CON1(md_topsm_base)); sync_write32(ioread32(MD_TOPSM_RM_PLL_MASK0(md_topsm_base)) | 0xFFFF0000, MD_TOPSM_RM_PLL_MASK0(md_topsm_base)); sync_write32(ioread32(MD_TOPSM_RM_PLL_MASK1(md_topsm_base)) | 0xFFFFFFFF, MD_TOPSM_RM_PLL_MASK1(md_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PLL_MASK0(modem_topsm_base)) | 0xFFFFFFFF, MODEM_TOPSM_RM_PLL_MASK0(modem_topsm_base)); sync_write32(ioread32(MODEM_TOPSM_RM_PLL_MASK1(modem_topsm_base)) | 0x0000000F, MODEM_TOPSM_RM_PLL_MASK1(modem_topsm_base)); sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PLL_MASK0(modem_lite_topsm_base)) | 0xFFFFFFFF, MODEM_LITE_TOPSM_RM_PLL_MASK0(modem_lite_topsm_base)); sync_write32(ioread32(MODEM_LITE_TOPSM_RM_PLL_MASK1(modem_lite_topsm_base)) | 0x0000000F, MODEM_LITE_TOPSM_RM_PLL_MASK1(modem_lite_topsm_base)); pr_debug("[ccci-off]7.power off CR4\n"); sync_write32(0xFFFFFFFF, MD_TOPSM_SM_REQ_MASK(md_topsm_base)); sync_write32(0x00000000, MD_TOPSM_RM_TMR_PWR0(md_topsm_base)); sync_write32(0x0005229A, MD_TOPSM_RM_PWR_CON0(md_topsm_base)); sync_write32(0xFFFFFFFF, MD_TOPSM_RM_PLL_MASK0(md_topsm_base)); sync_write32(0xFFFFFFFF, MD_TOPSM_RM_PLL_MASK1(md_topsm_base)); sync_write32(0xFFFFFFFF, MODEM_LITE_TOPSM_SM_REQ_MASK(modem_lite_topsm_base)); sync_write32(0xFFFFFFFF, MODEM_LITE_TOPSM_RM_PLL_MASK0(modem_lite_topsm_base)); sync_write32(0xFFFFFFFF, MODEM_LITE_TOPSM_RM_PLL_MASK1(modem_lite_topsm_base)); sync_write32(0xFFFFFFFF, MODEM_TOPSM_SM_REQ_MASK(modem_topsm_base)); sync_write32(0xFFFFFFFF, MODEM_TOPSM_RM_PLL_MASK0(modem_topsm_base)); sync_write32(0xFFFFFFFF, MODEM_TOPSM_RM_PLL_MASK1(modem_topsm_base)); pr_debug("[ccci-off]8.power off MD_INFRA/MODEM_TOP\n"); /* no need to poll, as MD SW didn't run and enter sleep mode, polling will not get result */ md_power_off(SYS_MD1, 0); iounmap(md_topsm_base); iounmap(modem_lite_topsm_base); iounmap(modem_topsm_base); iounmap(tdd_base); iounmap(ltelt1_base); iounmap(ltelt1_base_1); iounmap(ltelt1_base_2); iounmap(md_pll_mixedsys_base); }