18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci * Copyright 2017-2018 NXP. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/of_address.h> 118c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include "common.h" 148c2ecf20Sopenharmony_ci#include "hardware.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define REG_SET 0x4 178c2ecf20Sopenharmony_ci#define REG_CLR 0x8 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define ANADIG_REG_2P5 0x130 208c2ecf20Sopenharmony_ci#define ANADIG_REG_CORE 0x140 218c2ecf20Sopenharmony_ci#define ANADIG_ANA_MISC0 0x150 228c2ecf20Sopenharmony_ci#define ANADIG_DIGPROG 0x260 238c2ecf20Sopenharmony_ci#define ANADIG_DIGPROG_IMX6SL 0x280 248c2ecf20Sopenharmony_ci#define ANADIG_DIGPROG_IMX7D 0x800 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define SRC_SBMR2 0x1c 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 298c2ecf20Sopenharmony_ci#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 308c2ecf20Sopenharmony_ci#define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 318c2ecf20Sopenharmony_ci#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 328c2ecf20Sopenharmony_ci/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */ 338c2ecf20Sopenharmony_ci#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct regmap *anatop; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void imx_anatop_enable_weak2p5(bool enable) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci u32 reg, val; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci regmap_read(anatop, ANADIG_ANA_MISC0, &val); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* can only be enabled when stop_mode_config is clear. */ 448c2ecf20Sopenharmony_ci reg = ANADIG_REG_2P5; 458c2ecf20Sopenharmony_ci reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ? 468c2ecf20Sopenharmony_ci REG_SET : REG_CLR; 478c2ecf20Sopenharmony_ci regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void imx_anatop_enable_fet_odrive(bool enable) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR), 538c2ecf20Sopenharmony_ci BM_ANADIG_REG_CORE_FET_ODRIVE); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline void imx_anatop_enable_2p5_pulldown(bool enable) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR), 598c2ecf20Sopenharmony_ci BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline void imx_anatop_disconnect_high_snvs(bool enable) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), 658c2ecf20Sopenharmony_ci BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_civoid imx_anatop_pre_suspend(void) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) 718c2ecf20Sopenharmony_ci imx_anatop_enable_2p5_pulldown(true); 728c2ecf20Sopenharmony_ci else 738c2ecf20Sopenharmony_ci imx_anatop_enable_weak2p5(true); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci imx_anatop_enable_fet_odrive(true); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (cpu_is_imx6sl()) 788c2ecf20Sopenharmony_ci imx_anatop_disconnect_high_snvs(true); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_civoid imx_anatop_post_resume(void) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) 848c2ecf20Sopenharmony_ci imx_anatop_enable_2p5_pulldown(false); 858c2ecf20Sopenharmony_ci else 868c2ecf20Sopenharmony_ci imx_anatop_enable_weak2p5(false); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci imx_anatop_enable_fet_odrive(false); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (cpu_is_imx6sl()) 918c2ecf20Sopenharmony_ci imx_anatop_disconnect_high_snvs(false); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_civoid __init imx_init_revision_from_anatop(void) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct device_node *np, *src_np; 978c2ecf20Sopenharmony_ci void __iomem *anatop_base; 988c2ecf20Sopenharmony_ci unsigned int revision; 998c2ecf20Sopenharmony_ci u32 digprog; 1008c2ecf20Sopenharmony_ci u16 offset = ANADIG_DIGPROG; 1018c2ecf20Sopenharmony_ci u8 major_part, minor_part; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); 1048c2ecf20Sopenharmony_ci anatop_base = of_iomap(np, 0); 1058c2ecf20Sopenharmony_ci WARN_ON(!anatop_base); 1068c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx6sl-anatop")) 1078c2ecf20Sopenharmony_ci offset = ANADIG_DIGPROG_IMX6SL; 1088c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx7d-anatop")) 1098c2ecf20Sopenharmony_ci offset = ANADIG_DIGPROG_IMX7D; 1108c2ecf20Sopenharmony_ci digprog = readl_relaxed(anatop_base + offset); 1118c2ecf20Sopenharmony_ci iounmap(anatop_base); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * On i.MX7D digprog value match linux version format, so 1158c2ecf20Sopenharmony_ci * it needn't map again and we can use register value directly. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx7d-anatop")) { 1188c2ecf20Sopenharmony_ci revision = digprog & 0xff; 1198c2ecf20Sopenharmony_ci } else { 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * MAJOR: [15:8], the major silicon revison; 1228c2ecf20Sopenharmony_ci * MINOR: [7: 0], the minor silicon revison; 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * please refer to the i.MX RM for the detailed 1258c2ecf20Sopenharmony_ci * silicon revison bit define. 1268c2ecf20Sopenharmony_ci * format the major part and minor part to match the 1278c2ecf20Sopenharmony_ci * linux kernel soc version format. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci major_part = (digprog >> 8) & 0xf; 1308c2ecf20Sopenharmony_ci minor_part = digprog & 0xf; 1318c2ecf20Sopenharmony_ci revision = ((major_part + 1) << 4) | minor_part; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if ((digprog >> 16) == MXC_CPU_IMX6ULL) { 1348c2ecf20Sopenharmony_ci void __iomem *src_base; 1358c2ecf20Sopenharmony_ci u32 sbmr2; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci src_np = of_find_compatible_node(NULL, NULL, 1388c2ecf20Sopenharmony_ci "fsl,imx6ul-src"); 1398c2ecf20Sopenharmony_ci src_base = of_iomap(src_np, 0); 1408c2ecf20Sopenharmony_ci of_node_put(src_np); 1418c2ecf20Sopenharmony_ci WARN_ON(!src_base); 1428c2ecf20Sopenharmony_ci sbmr2 = readl_relaxed(src_base + SRC_SBMR2); 1438c2ecf20Sopenharmony_ci iounmap(src_base); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* src_sbmr2 bit 6 is to identify if it is i.MX6ULZ */ 1468c2ecf20Sopenharmony_ci if (sbmr2 & (1 << 6)) { 1478c2ecf20Sopenharmony_ci digprog &= ~(0xff << 16); 1488c2ecf20Sopenharmony_ci digprog |= (MXC_CPU_IMX6ULZ << 16); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci of_node_put(np); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci mxc_set_cpu_type(digprog >> 16 & 0xff); 1558c2ecf20Sopenharmony_ci imx_set_soc_revision(revision); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_civoid __init imx_anatop_init(void) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); 1618c2ecf20Sopenharmony_ci if (IS_ERR(anatop)) 1628c2ecf20Sopenharmony_ci pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); 1638c2ecf20Sopenharmony_ci} 164