xref: /linux/arch/arm/mach-imx/mach-imx6q.c (revision b889fcf63cb62e7fdb7816565e28f44dbe4a76a5)
1 /*
2  * Copyright 2011 Freescale Semiconductor, Inc.
3  * Copyright 2011 Linaro Ltd.
4  *
5  * The code contained herein is licensed under the GNU General Public
6  * License. You may obtain a copy of the GNU General Public License
7  * Version 2 or later at the following locations:
8  *
9  * http://www.opensource.org/licenses/gpl-license.html
10  * http://www.gnu.org/copyleft/gpl.html
11  */
12 
13 #include <linux/clk.h>
14 #include <linux/clkdev.h>
15 #include <linux/cpuidle.h>
16 #include <linux/delay.h>
17 #include <linux/export.h>
18 #include <linux/init.h>
19 #include <linux/io.h>
20 #include <linux/irq.h>
21 #include <linux/of.h>
22 #include <linux/of_address.h>
23 #include <linux/of_irq.h>
24 #include <linux/of_platform.h>
25 #include <linux/phy.h>
26 #include <linux/regmap.h>
27 #include <linux/micrel_phy.h>
28 #include <linux/mfd/syscon.h>
29 #include <asm/cpuidle.h>
30 #include <asm/smp_twd.h>
31 #include <asm/hardware/cache-l2x0.h>
32 #include <asm/hardware/gic.h>
33 #include <asm/mach/arch.h>
34 #include <asm/mach/time.h>
35 #include <asm/system_misc.h>
36 
37 #include "common.h"
38 #include "cpuidle.h"
39 #include "hardware.h"
40 
41 #define IMX6Q_ANALOG_DIGPROG	0x260
42 
43 static int imx6q_revision(void)
44 {
45 	struct device_node *np;
46 	void __iomem *base;
47 	static u32 rev;
48 
49 	if (!rev) {
50 		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
51 		if (!np)
52 			return IMX_CHIP_REVISION_UNKNOWN;
53 		base = of_iomap(np, 0);
54 		if (!base) {
55 			of_node_put(np);
56 			return IMX_CHIP_REVISION_UNKNOWN;
57 		}
58 		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG);
59 		iounmap(base);
60 		of_node_put(np);
61 	}
62 
63 	switch (rev & 0xff) {
64 	case 0:
65 		return IMX_CHIP_REVISION_1_0;
66 	case 1:
67 		return IMX_CHIP_REVISION_1_1;
68 	case 2:
69 		return IMX_CHIP_REVISION_1_2;
70 	default:
71 		return IMX_CHIP_REVISION_UNKNOWN;
72 	}
73 }
74 
75 void imx6q_restart(char mode, const char *cmd)
76 {
77 	struct device_node *np;
78 	void __iomem *wdog_base;
79 
80 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-wdt");
81 	wdog_base = of_iomap(np, 0);
82 	if (!wdog_base)
83 		goto soft;
84 
85 	imx_src_prepare_restart();
86 
87 	/* enable wdog */
88 	writew_relaxed(1 << 2, wdog_base);
89 	/* write twice to ensure the request will not get ignored */
90 	writew_relaxed(1 << 2, wdog_base);
91 
92 	/* wait for reset to assert ... */
93 	mdelay(500);
94 
95 	pr_err("Watchdog reset failed to assert reset\n");
96 
97 	/* delay to allow the serial port to show the message */
98 	mdelay(50);
99 
100 soft:
101 	/* we'll take a jump through zero as a poor second */
102 	soft_restart(0);
103 }
104 
105 /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
106 static int ksz9021rn_phy_fixup(struct phy_device *phydev)
107 {
108 	if (IS_BUILTIN(CONFIG_PHYLIB)) {
109 		/* min rx data delay */
110 		phy_write(phydev, 0x0b, 0x8105);
111 		phy_write(phydev, 0x0c, 0x0000);
112 
113 		/* max rx/tx clock delay, min rx/tx control delay */
114 		phy_write(phydev, 0x0b, 0x8104);
115 		phy_write(phydev, 0x0c, 0xf0f0);
116 		phy_write(phydev, 0x0b, 0x104);
117 	}
118 
119 	return 0;
120 }
121 
122 static void __init imx6q_sabrelite_cko1_setup(void)
123 {
124 	struct clk *cko1_sel, *ahb, *cko1;
125 	unsigned long rate;
126 
127 	cko1_sel = clk_get_sys(NULL, "cko1_sel");
128 	ahb = clk_get_sys(NULL, "ahb");
129 	cko1 = clk_get_sys(NULL, "cko1");
130 	if (IS_ERR(cko1_sel) || IS_ERR(ahb) || IS_ERR(cko1)) {
131 		pr_err("cko1 setup failed!\n");
132 		goto put_clk;
133 	}
134 	clk_set_parent(cko1_sel, ahb);
135 	rate = clk_round_rate(cko1, 16000000);
136 	clk_set_rate(cko1, rate);
137 put_clk:
138 	if (!IS_ERR(cko1_sel))
139 		clk_put(cko1_sel);
140 	if (!IS_ERR(ahb))
141 		clk_put(ahb);
142 	if (!IS_ERR(cko1))
143 		clk_put(cko1);
144 }
145 
146 static void __init imx6q_sabrelite_init(void)
147 {
148 	if (IS_BUILTIN(CONFIG_PHYLIB))
149 		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
150 				ksz9021rn_phy_fixup);
151 	imx6q_sabrelite_cko1_setup();
152 }
153 
154 static void __init imx6q_1588_init(void)
155 {
156 	struct regmap *gpr;
157 
158 	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
159 	if (!IS_ERR(gpr))
160 		regmap_update_bits(gpr, 0x4, 1 << 21, 1 << 21);
161 	else
162 		pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n");
163 
164 }
165 static void __init imx6q_usb_init(void)
166 {
167 	struct regmap *anatop;
168 
169 #define HW_ANADIG_USB1_CHRG_DETECT		0x000001b0
170 #define HW_ANADIG_USB2_CHRG_DETECT		0x00000210
171 
172 #define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x00100000
173 #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x00080000
174 
175 	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
176 	if (!IS_ERR(anatop)) {
177 		/*
178 		 * The external charger detector needs to be disabled,
179 		 * or the signal at DP will be poor
180 		 */
181 		regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT,
182 				BM_ANADIG_USB_CHRG_DETECT_EN_B
183 				| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
184 		regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT,
185 				BM_ANADIG_USB_CHRG_DETECT_EN_B |
186 				BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
187 	} else {
188 		pr_warn("failed to find fsl,imx6q-anatop regmap\n");
189 	}
190 }
191 
192 static void __init imx6q_init_machine(void)
193 {
194 	if (of_machine_is_compatible("fsl,imx6q-sabrelite"))
195 		imx6q_sabrelite_init();
196 
197 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
198 
199 	imx6q_pm_init();
200 	imx6q_usb_init();
201 	imx6q_1588_init();
202 }
203 
204 static struct cpuidle_driver imx6q_cpuidle_driver = {
205 	.name			= "imx6q_cpuidle",
206 	.owner			= THIS_MODULE,
207 	.en_core_tk_irqen	= 1,
208 	.states[0]		= ARM_CPUIDLE_WFI_STATE,
209 	.state_count		= 1,
210 };
211 
212 static void __init imx6q_init_late(void)
213 {
214 	imx_cpuidle_init(&imx6q_cpuidle_driver);
215 }
216 
217 static void __init imx6q_map_io(void)
218 {
219 	imx_lluart_map_io();
220 	imx_scu_map_io();
221 	imx6q_clock_map_io();
222 }
223 
224 static const struct of_device_id imx6q_irq_match[] __initconst = {
225 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
226 	{ /* sentinel */ }
227 };
228 
229 static void __init imx6q_init_irq(void)
230 {
231 	l2x0_of_init(0, ~0UL);
232 	imx_src_init();
233 	imx_gpc_init();
234 	of_irq_init(imx6q_irq_match);
235 }
236 
237 static void __init imx6q_timer_init(void)
238 {
239 	mx6q_clocks_init();
240 	twd_local_timer_of_register();
241 	imx_print_silicon_rev("i.MX6Q", imx6q_revision());
242 }
243 
244 static struct sys_timer imx6q_timer = {
245 	.init = imx6q_timer_init,
246 };
247 
248 static const char *imx6q_dt_compat[] __initdata = {
249 	"fsl,imx6q",
250 	NULL,
251 };
252 
253 DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)")
254 	.smp		= smp_ops(imx_smp_ops),
255 	.map_io		= imx6q_map_io,
256 	.init_irq	= imx6q_init_irq,
257 	.handle_irq	= imx6q_handle_irq,
258 	.timer		= &imx6q_timer,
259 	.init_machine	= imx6q_init_machine,
260 	.init_late      = imx6q_init_late,
261 	.dt_compat	= imx6q_dt_compat,
262 	.restart	= imx6q_restart,
263 MACHINE_END
264