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 void __init imx_init_revision_from_anatop(void) 95 { 96 struct device_node *np, *src_np; 97 void __iomem *anatop_base; 98 unsigned int revision; 99 u32 digprog; 100 u16 offset = ANADIG_DIGPROG; 101 u8 major_part, minor_part; 102 103 np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); 104 anatop_base = of_iomap(np, 0); 105 WARN_ON(!anatop_base); 106 if (of_device_is_compatible(np, "fsl,imx6sl-anatop")) 107 offset = ANADIG_DIGPROG_IMX6SL; 108 if (of_device_is_compatible(np, "fsl,imx7d-anatop")) 109 offset = ANADIG_DIGPROG_IMX7D; 110 digprog = readl_relaxed(anatop_base + offset); 111 iounmap(anatop_base); 112 113 /* 114 * On i.MX7D digprog value match linux version format, so 115 * it needn't map again and we can use register value directly. 116 */ 117 if (of_device_is_compatible(np, "fsl,imx7d-anatop")) { 118 revision = digprog & 0xff; 119 } else { 120 /* 121 * MAJOR: [15:8], the major silicon revison; 122 * MINOR: [7: 0], the minor silicon revison; 123 * 124 * please refer to the i.MX RM for the detailed 125 * silicon revison bit define. 126 * format the major part and minor part to match the 127 * linux kernel soc version format. 128 */ 129 major_part = (digprog >> 8) & 0xf; 130 minor_part = digprog & 0xf; 131 revision = ((major_part + 1) << 4) | minor_part; 132 133 if ((digprog >> 16) == MXC_CPU_IMX6ULL) { 134 void __iomem *src_base; 135 u32 sbmr2; 136 137 src_np = of_find_compatible_node(NULL, NULL, 138 "fsl,imx6ul-src"); 139 src_base = of_iomap(np, 0); 140 of_node_put(src_np); 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 of_node_put(np); 153 154 mxc_set_cpu_type(digprog >> 16 & 0xff); 155 imx_set_soc_revision(revision); 156 } 157 158 void __init imx_anatop_init(void) 159 { 160 anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); 161 if (IS_ERR(anatop)) 162 pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); 163 } 164