xref: /openbmc/linux/arch/arm/mach-imx/anatop.c (revision c90dec00)
1e95dddb3SAnson Huang /*
25739b919SAnson Huang  * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
3261b3503SBai Ping  * Copyright 2017-2018 NXP.
4e95dddb3SAnson Huang  *
5e95dddb3SAnson Huang  * The code contained herein is licensed under the GNU General Public
6e95dddb3SAnson Huang  * License. You may obtain a copy of the GNU General Public License
7e95dddb3SAnson Huang  * Version 2 or later at the following locations:
8e95dddb3SAnson Huang  *
9e95dddb3SAnson Huang  * http://www.opensource.org/licenses/gpl-license.html
10e95dddb3SAnson Huang  * http://www.gnu.org/copyleft/gpl.html
11e95dddb3SAnson Huang  */
12e95dddb3SAnson Huang 
13e95dddb3SAnson Huang #include <linux/err.h>
14e95dddb3SAnson Huang #include <linux/io.h>
15e95dddb3SAnson Huang #include <linux/of.h>
16e95dddb3SAnson Huang #include <linux/of_address.h>
17e95dddb3SAnson Huang #include <linux/mfd/syscon.h>
18e95dddb3SAnson Huang #include <linux/regmap.h>
19fcc4f9fcSFabio Estevam #include "common.h"
20f1c6f314SShawn Guo #include "hardware.h"
21e95dddb3SAnson Huang 
22e95dddb3SAnson Huang #define REG_SET		0x4
23e95dddb3SAnson Huang #define REG_CLR		0x8
24e95dddb3SAnson Huang 
25263475d4SAnson Huang #define ANADIG_REG_2P5		0x130
26e95dddb3SAnson Huang #define ANADIG_REG_CORE		0x140
27263475d4SAnson Huang #define ANADIG_ANA_MISC0	0x150
28e95dddb3SAnson Huang #define ANADIG_USB1_CHRG_DETECT	0x1b0
29e95dddb3SAnson Huang #define ANADIG_USB2_CHRG_DETECT	0x210
30e95dddb3SAnson Huang #define ANADIG_DIGPROG		0x260
31d8ce823fSShawn Guo #define ANADIG_DIGPROG_IMX6SL	0x280
325739b919SAnson Huang #define ANADIG_DIGPROG_IMX7D	0x800
33e95dddb3SAnson Huang 
34c90dec00SAnson Huang #define SRC_SBMR2		0x1c
35c90dec00SAnson Huang 
36263475d4SAnson Huang #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG	0x40000
37bc4abc3eSAnson Huang #define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN	0x8
38e95dddb3SAnson Huang #define BM_ANADIG_REG_CORE_FET_ODRIVE		0x20000000
39263475d4SAnson Huang #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	0x1000
40bc4abc3eSAnson Huang /* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
41bc4abc3eSAnson Huang #define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS	0x2000
42e95dddb3SAnson Huang #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x80000
43e95dddb3SAnson Huang #define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x100000
44e95dddb3SAnson Huang 
45e95dddb3SAnson Huang static struct regmap *anatop;
46e95dddb3SAnson Huang 
47263475d4SAnson Huang static void imx_anatop_enable_weak2p5(bool enable)
48263475d4SAnson Huang {
49263475d4SAnson Huang 	u32 reg, val;
50263475d4SAnson Huang 
51263475d4SAnson Huang 	regmap_read(anatop, ANADIG_ANA_MISC0, &val);
52263475d4SAnson Huang 
53263475d4SAnson Huang 	/* can only be enabled when stop_mode_config is clear. */
54263475d4SAnson Huang 	reg = ANADIG_REG_2P5;
55263475d4SAnson Huang 	reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ?
56263475d4SAnson Huang 		REG_SET : REG_CLR;
57263475d4SAnson Huang 	regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG);
58263475d4SAnson Huang }
59263475d4SAnson Huang 
60e95dddb3SAnson Huang static void imx_anatop_enable_fet_odrive(bool enable)
61e95dddb3SAnson Huang {
62e95dddb3SAnson Huang 	regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR),
63e95dddb3SAnson Huang 		BM_ANADIG_REG_CORE_FET_ODRIVE);
64e95dddb3SAnson Huang }
65e95dddb3SAnson Huang 
66bc4abc3eSAnson Huang static inline void imx_anatop_enable_2p5_pulldown(bool enable)
67bc4abc3eSAnson Huang {
68bc4abc3eSAnson Huang 	regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR),
69bc4abc3eSAnson Huang 		BM_ANADIG_REG_2P5_ENABLE_PULLDOWN);
70bc4abc3eSAnson Huang }
71bc4abc3eSAnson Huang 
72bc4abc3eSAnson Huang static inline void imx_anatop_disconnect_high_snvs(bool enable)
73bc4abc3eSAnson Huang {
74bc4abc3eSAnson Huang 	regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR),
75bc4abc3eSAnson Huang 		BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS);
76bc4abc3eSAnson Huang }
77bc4abc3eSAnson Huang 
78e95dddb3SAnson Huang void imx_anatop_pre_suspend(void)
79e95dddb3SAnson Huang {
80bc4abc3eSAnson Huang 	if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
81bc4abc3eSAnson Huang 		imx_anatop_enable_2p5_pulldown(true);
82bc4abc3eSAnson Huang 	else
83263475d4SAnson Huang 		imx_anatop_enable_weak2p5(true);
84bc4abc3eSAnson Huang 
85e95dddb3SAnson Huang 	imx_anatop_enable_fet_odrive(true);
86bc4abc3eSAnson Huang 
87bc4abc3eSAnson Huang 	if (cpu_is_imx6sl())
88bc4abc3eSAnson Huang 		imx_anatop_disconnect_high_snvs(true);
89e95dddb3SAnson Huang }
90e95dddb3SAnson Huang 
91e95dddb3SAnson Huang void imx_anatop_post_resume(void)
92e95dddb3SAnson Huang {
93bc4abc3eSAnson Huang 	if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
94bc4abc3eSAnson Huang 		imx_anatop_enable_2p5_pulldown(false);
95bc4abc3eSAnson Huang 	else
96263475d4SAnson Huang 		imx_anatop_enable_weak2p5(false);
97bc4abc3eSAnson Huang 
98bc4abc3eSAnson Huang 	imx_anatop_enable_fet_odrive(false);
99bc4abc3eSAnson Huang 
100bc4abc3eSAnson Huang 	if (cpu_is_imx6sl())
101bc4abc3eSAnson Huang 		imx_anatop_disconnect_high_snvs(false);
102bc4abc3eSAnson Huang 
103e95dddb3SAnson Huang }
104e95dddb3SAnson Huang 
105ddcb9aa6SPeter Chen static void imx_anatop_usb_chrg_detect_disable(void)
106e95dddb3SAnson Huang {
107e95dddb3SAnson Huang 	regmap_write(anatop, ANADIG_USB1_CHRG_DETECT,
108e95dddb3SAnson Huang 		BM_ANADIG_USB_CHRG_DETECT_EN_B
109e95dddb3SAnson Huang 		| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
110e95dddb3SAnson Huang 	regmap_write(anatop, ANADIG_USB2_CHRG_DETECT,
111e95dddb3SAnson Huang 		BM_ANADIG_USB_CHRG_DETECT_EN_B |
112e95dddb3SAnson Huang 		BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
113e95dddb3SAnson Huang }
114e95dddb3SAnson Huang 
115f1c6f314SShawn Guo void __init imx_init_revision_from_anatop(void)
116e95dddb3SAnson Huang {
1177006ba24SShawn Guo 	struct device_node *np;
1187006ba24SShawn Guo 	void __iomem *anatop_base;
119f1c6f314SShawn Guo 	unsigned int revision;
120f1c6f314SShawn Guo 	u32 digprog;
121d8ce823fSShawn Guo 	u16 offset = ANADIG_DIGPROG;
122261b3503SBai Ping 	u8 major_part, minor_part;
1237006ba24SShawn Guo 
1247006ba24SShawn Guo 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
1257006ba24SShawn Guo 	anatop_base = of_iomap(np, 0);
1267006ba24SShawn Guo 	WARN_ON(!anatop_base);
127d8ce823fSShawn Guo 	if (of_device_is_compatible(np, "fsl,imx6sl-anatop"))
128d8ce823fSShawn Guo 		offset = ANADIG_DIGPROG_IMX6SL;
1295739b919SAnson Huang 	if (of_device_is_compatible(np, "fsl,imx7d-anatop"))
1305739b919SAnson Huang 		offset = ANADIG_DIGPROG_IMX7D;
131d8ce823fSShawn Guo 	digprog = readl_relaxed(anatop_base + offset);
132f1c6f314SShawn Guo 	iounmap(anatop_base);
1337006ba24SShawn Guo 
134c5a890a4SBai Ping 	/*
135261b3503SBai Ping 	 * On i.MX7D digprog value match linux version format, so
136261b3503SBai Ping 	 * it needn't map again and we can use register value directly.
137c5a890a4SBai Ping 	 */
138261b3503SBai Ping 	if (of_device_is_compatible(np, "fsl,imx7d-anatop")) {
139e914ecebSFrank Li 		revision = digprog & 0xff;
140261b3503SBai Ping 	} else {
141261b3503SBai Ping 		/*
142261b3503SBai Ping 		 * MAJOR: [15:8], the major silicon revison;
143261b3503SBai Ping 		 * MINOR: [7: 0], the minor silicon revison;
144261b3503SBai Ping 		 *
145261b3503SBai Ping 		 * please refer to the i.MX RM for the detailed
146261b3503SBai Ping 		 * silicon revison bit define.
147261b3503SBai Ping 		 * format the major part and minor part to match the
148261b3503SBai Ping 		 * linux kernel soc version format.
149261b3503SBai Ping 		 */
150261b3503SBai Ping 		major_part = (digprog >> 8) & 0xf;
151261b3503SBai Ping 		minor_part = digprog & 0xf;
152261b3503SBai Ping 		revision = ((major_part + 1) << 4) | minor_part;
153c90dec00SAnson Huang 
154c90dec00SAnson Huang 		if ((digprog >> 16) == MXC_CPU_IMX6ULL) {
155c90dec00SAnson Huang 			void __iomem *src_base;
156c90dec00SAnson Huang 			u32 sbmr2;
157c90dec00SAnson Huang 
158c90dec00SAnson Huang 			np = of_find_compatible_node(NULL, NULL,
159c90dec00SAnson Huang 						     "fsl,imx6ul-src");
160c90dec00SAnson Huang 			src_base = of_iomap(np, 0);
161c90dec00SAnson Huang 			WARN_ON(!src_base);
162c90dec00SAnson Huang 			sbmr2 = readl_relaxed(src_base + SRC_SBMR2);
163c90dec00SAnson Huang 			iounmap(src_base);
164c90dec00SAnson Huang 
165c90dec00SAnson Huang 			/* src_sbmr2 bit 6 is to identify if it is i.MX6ULZ */
166c90dec00SAnson Huang 			if (sbmr2 & (1 << 6)) {
167c90dec00SAnson Huang 				digprog &= ~(0xff << 16);
168c90dec00SAnson Huang 				digprog |= (MXC_CPU_IMX6ULZ << 16);
169c90dec00SAnson Huang 			}
170c90dec00SAnson Huang 		}
171f1c6f314SShawn Guo 	}
172f1c6f314SShawn Guo 
173f1c6f314SShawn Guo 	mxc_set_cpu_type(digprog >> 16 & 0xff);
174f1c6f314SShawn Guo 	imx_set_soc_revision(revision);
175e95dddb3SAnson Huang }
176e95dddb3SAnson Huang 
177e95dddb3SAnson Huang void __init imx_anatop_init(void)
178e95dddb3SAnson Huang {
179e95dddb3SAnson Huang 	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
180e95dddb3SAnson Huang 	if (IS_ERR(anatop)) {
181e95dddb3SAnson Huang 		pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__);
182e95dddb3SAnson Huang 		return;
183e95dddb3SAnson Huang 	}
184ddcb9aa6SPeter Chen 
185ddcb9aa6SPeter Chen 	imx_anatop_usb_chrg_detect_disable();
186e95dddb3SAnson Huang }
187