1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. 4 * Copyright 2017-2018 NXP. 5 */ 6 7 #include <linux/err.h> 8 #include <linux/io.h> 9 #include <linux/of.h> 10 #include <linux/of_address.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/regmap.h> 13 #include "common.h" 14 #include "hardware.h" 15 16 #define REG_SET 0x4 17 #define REG_CLR 0x8 18 19 #define ANADIG_REG_2P5 0x130 20 #define ANADIG_REG_CORE 0x140 21 #define ANADIG_ANA_MISC0 0x150 22 #define ANADIG_DIGPROG 0x260 23 #define ANADIG_DIGPROG_IMX6SL 0x280 24 #define ANADIG_DIGPROG_IMX7D 0x800 25 26 #define SRC_SBMR2 0x1c 27 28 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 29 #define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 30 #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 31 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 32 /* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */ 33 #define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 34 35 static struct regmap *anatop; 36 37 static void imx_anatop_enable_weak2p5(bool enable) 38 { 39 u32 reg, val; 40 41 regmap_read(anatop, ANADIG_ANA_MISC0, &val); 42 43 /* can only be enabled when stop_mode_config is clear. */ 44 reg = ANADIG_REG_2P5; 45 reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ? 46 REG_SET : REG_CLR; 47 regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG); 48 } 49 50 static void imx_anatop_enable_fet_odrive(bool enable) 51 { 52 regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR), 53 BM_ANADIG_REG_CORE_FET_ODRIVE); 54 } 55 56 static inline void imx_anatop_enable_2p5_pulldown(bool enable) 57 { 58 regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR), 59 BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); 60 } 61 62 static inline void imx_anatop_disconnect_high_snvs(bool enable) 63 { 64 regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), 65 BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); 66 } 67 68 void imx_anatop_pre_suspend(void) 69 { 70 if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) 71 imx_anatop_enable_2p5_pulldown(true); 72 else 73 imx_anatop_enable_weak2p5(true); 74 75 imx_anatop_enable_fet_odrive(true); 76 77 if (cpu_is_imx6sl()) 78 imx_anatop_disconnect_high_snvs(true); 79 } 80 81 void imx_anatop_post_resume(void) 82 { 83 if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) 84 imx_anatop_enable_2p5_pulldown(false); 85 else 86 imx_anatop_enable_weak2p5(false); 87 88 imx_anatop_enable_fet_odrive(false); 89 90 if (cpu_is_imx6sl()) 91 imx_anatop_disconnect_high_snvs(false); 92 93 } 94 95 void __init imx_init_revision_from_anatop(void) 96 { 97 struct device_node *np; 98 void __iomem *anatop_base; 99 unsigned int revision; 100 u32 digprog; 101 u16 offset = ANADIG_DIGPROG; 102 u8 major_part, minor_part; 103 104 np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); 105 anatop_base = of_iomap(np, 0); 106 WARN_ON(!anatop_base); 107 if (of_device_is_compatible(np, "fsl,imx6sl-anatop")) 108 offset = ANADIG_DIGPROG_IMX6SL; 109 if (of_device_is_compatible(np, "fsl,imx7d-anatop")) 110 offset = ANADIG_DIGPROG_IMX7D; 111 digprog = readl_relaxed(anatop_base + offset); 112 iounmap(anatop_base); 113 114 /* 115 * On i.MX7D digprog value match linux version format, so 116 * it needn't map again and we can use register value directly. 117 */ 118 if (of_device_is_compatible(np, "fsl,imx7d-anatop")) { 119 revision = digprog & 0xff; 120 } else { 121 /* 122 * MAJOR: [15:8], the major silicon revison; 123 * MINOR: [7: 0], the minor silicon revison; 124 * 125 * please refer to the i.MX RM for the detailed 126 * silicon revison bit define. 127 * format the major part and minor part to match the 128 * linux kernel soc version format. 129 */ 130 major_part = (digprog >> 8) & 0xf; 131 minor_part = digprog & 0xf; 132 revision = ((major_part + 1) << 4) | minor_part; 133 134 if ((digprog >> 16) == MXC_CPU_IMX6ULL) { 135 void __iomem *src_base; 136 u32 sbmr2; 137 138 np = of_find_compatible_node(NULL, NULL, 139 "fsl,imx6ul-src"); 140 src_base = of_iomap(np, 0); 141 WARN_ON(!src_base); 142 sbmr2 = readl_relaxed(src_base + SRC_SBMR2); 143 iounmap(src_base); 144 145 /* src_sbmr2 bit 6 is to identify if it is i.MX6ULZ */ 146 if (sbmr2 & (1 << 6)) { 147 digprog &= ~(0xff << 16); 148 digprog |= (MXC_CPU_IMX6ULZ << 16); 149 } 150 } 151 } 152 153 mxc_set_cpu_type(digprog >> 16 & 0xff); 154 imx_set_soc_revision(revision); 155 } 156 157 void __init imx_anatop_init(void) 158 { 159 anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); 160 if (IS_ERR(anatop)) 161 pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); 162 } 163