anatop.c (4348B)
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 35static struct regmap *anatop; 36 37static 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 50static 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 56static 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 62static 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 68void 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 81void 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 94void __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(src_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 158void __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}