Commit | Line | Data |
---|---|---|
bc3a59c1 DA |
1 | /* |
2 | * Copyright 2012 Freescale Semiconductor, Inc. | |
3 | * Copyright 2012 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> | |
3cb7825b | 14 | #include <linux/clk/mxs.h> |
bc3a59c1 | 15 | #include <linux/clkdev.h> |
633ef4c7 | 16 | #include <linux/clocksource.h> |
44ffb78f | 17 | #include <linux/can/platform/flexcan.h> |
2c7c2c1d | 18 | #include <linux/delay.h> |
bc3a59c1 | 19 | #include <linux/err.h> |
2c7c2c1d | 20 | #include <linux/gpio.h> |
bc3a59c1 | 21 | #include <linux/init.h> |
6a8e95b0 | 22 | #include <linux/irqchip/mxs.h> |
7b6d864b | 23 | #include <linux/reboot.h> |
3143bbb4 | 24 | #include <linux/micrel_phy.h> |
974a9af5 | 25 | #include <linux/of_address.h> |
bc3a59c1 | 26 | #include <linux/of_platform.h> |
3143bbb4 | 27 | #include <linux/phy.h> |
2c7c2c1d | 28 | #include <linux/pinctrl/consumer.h> |
2046338d | 29 | #include <linux/sys_soc.h> |
bc3a59c1 | 30 | #include <asm/mach/arch.h> |
1f629564 | 31 | #include <asm/mach/map.h> |
bc3a59c1 | 32 | #include <asm/mach/time.h> |
974a9af5 | 33 | #include <asm/system_misc.h> |
0b48d3a6 | 34 | |
45680995 SG |
35 | #include "pm.h" |
36 | ||
0b48d3a6 SG |
37 | /* MXS DIGCTL SAIF CLKMUX */ |
38 | #define MXS_DIGCTL_SAIF_CLKMUX_DIRECT 0x0 | |
39 | #define MXS_DIGCTL_SAIF_CLKMUX_CROSSINPUT 0x1 | |
40 | #define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0 0x2 | |
41 | #define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR1 0x3 | |
42 | ||
2046338d FE |
43 | #define HW_DIGCTL_CHIPID 0x310 |
44 | #define HW_DIGCTL_CHIPID_MASK (0xffff << 16) | |
45 | #define HW_DIGCTL_REV_MASK 0xff | |
46 | #define HW_DIGCTL_CHIPID_MX23 (0x3780 << 16) | |
47 | #define HW_DIGCTL_CHIPID_MX28 (0x2800 << 16) | |
48 | ||
49 | #define MXS_CHIP_REVISION_1_0 0x10 | |
50 | #define MXS_CHIP_REVISION_1_1 0x11 | |
51 | #define MXS_CHIP_REVISION_1_2 0x12 | |
52 | #define MXS_CHIP_REVISION_1_3 0x13 | |
53 | #define MXS_CHIP_REVISION_1_4 0x14 | |
54 | #define MXS_CHIP_REV_UNKNOWN 0xff | |
55 | ||
0b48d3a6 SG |
56 | #define MXS_GPIO_NR(bank, nr) ((bank) * 32 + (nr)) |
57 | ||
58 | #define MXS_SET_ADDR 0x4 | |
59 | #define MXS_CLR_ADDR 0x8 | |
60 | #define MXS_TOG_ADDR 0xc | |
61 | ||
2046338d FE |
62 | static u32 chipid; |
63 | static u32 socid; | |
64 | ||
0b48d3a6 SG |
65 | static inline void __mxs_setl(u32 mask, void __iomem *reg) |
66 | { | |
67 | __raw_writel(mask, reg + MXS_SET_ADDR); | |
68 | } | |
69 | ||
70 | static inline void __mxs_clrl(u32 mask, void __iomem *reg) | |
71 | { | |
72 | __raw_writel(mask, reg + MXS_CLR_ADDR); | |
73 | } | |
74 | ||
75 | static inline void __mxs_togl(u32 mask, void __iomem *reg) | |
76 | { | |
77 | __raw_writel(mask, reg + MXS_TOG_ADDR); | |
78 | } | |
bc3a59c1 | 79 | |
44ffb78f SG |
80 | /* |
81 | * MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers | |
82 | */ | |
83 | #define MX28EVK_FLEXCAN_SWITCH MXS_GPIO_NR(2, 13) | |
84 | ||
85 | static int flexcan0_en, flexcan1_en; | |
86 | ||
87 | static void mx28evk_flexcan_switch(void) | |
88 | { | |
89 | if (flexcan0_en || flexcan1_en) | |
90 | gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 1); | |
91 | else | |
92 | gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 0); | |
93 | } | |
94 | ||
95 | static void mx28evk_flexcan0_switch(int enable) | |
96 | { | |
97 | flexcan0_en = enable; | |
98 | mx28evk_flexcan_switch(); | |
99 | } | |
100 | ||
101 | static void mx28evk_flexcan1_switch(int enable) | |
102 | { | |
103 | flexcan1_en = enable; | |
104 | mx28evk_flexcan_switch(); | |
105 | } | |
106 | ||
107 | static struct flexcan_platform_data flexcan_pdata[2]; | |
108 | ||
ab2815c3 | 109 | static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = { |
44ffb78f SG |
110 | OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80032000, NULL, &flexcan_pdata[0]), |
111 | OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80034000, NULL, &flexcan_pdata[1]), | |
ab2815c3 SG |
112 | { /* sentinel */ } |
113 | }; | |
114 | ||
1bff2d76 SG |
115 | #define OCOTP_WORD_OFFSET 0x20 |
116 | #define OCOTP_WORD_COUNT 0x20 | |
117 | ||
118 | #define BM_OCOTP_CTRL_BUSY (1 << 8) | |
119 | #define BM_OCOTP_CTRL_ERROR (1 << 9) | |
120 | #define BM_OCOTP_CTRL_RD_BANK_OPEN (1 << 12) | |
121 | ||
122 | static DEFINE_MUTEX(ocotp_mutex); | |
123 | static u32 ocotp_words[OCOTP_WORD_COUNT]; | |
124 | ||
125 | static const u32 *mxs_get_ocotp(void) | |
126 | { | |
127 | struct device_node *np; | |
128 | void __iomem *ocotp_base; | |
129 | int timeout = 0x400; | |
130 | size_t i; | |
131 | static int once; | |
132 | ||
133 | if (once) | |
134 | return ocotp_words; | |
135 | ||
136 | np = of_find_compatible_node(NULL, NULL, "fsl,ocotp"); | |
137 | ocotp_base = of_iomap(np, 0); | |
138 | WARN_ON(!ocotp_base); | |
139 | ||
140 | mutex_lock(&ocotp_mutex); | |
141 | ||
142 | /* | |
143 | * clk_enable(hbus_clk) for ocotp can be skipped | |
144 | * as it must be on when system is running. | |
145 | */ | |
146 | ||
147 | /* try to clear ERROR bit */ | |
148 | __mxs_clrl(BM_OCOTP_CTRL_ERROR, ocotp_base); | |
149 | ||
150 | /* check both BUSY and ERROR cleared */ | |
151 | while ((__raw_readl(ocotp_base) & | |
152 | (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR)) && --timeout) | |
153 | cpu_relax(); | |
154 | ||
155 | if (unlikely(!timeout)) | |
156 | goto error_unlock; | |
157 | ||
158 | /* open OCOTP banks for read */ | |
159 | __mxs_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base); | |
160 | ||
161 | /* approximately wait 32 hclk cycles */ | |
162 | udelay(1); | |
163 | ||
164 | /* poll BUSY bit becoming cleared */ | |
165 | timeout = 0x400; | |
166 | while ((__raw_readl(ocotp_base) & BM_OCOTP_CTRL_BUSY) && --timeout) | |
167 | cpu_relax(); | |
168 | ||
169 | if (unlikely(!timeout)) | |
170 | goto error_unlock; | |
171 | ||
172 | for (i = 0; i < OCOTP_WORD_COUNT; i++) | |
173 | ocotp_words[i] = __raw_readl(ocotp_base + OCOTP_WORD_OFFSET + | |
174 | i * 0x10); | |
175 | ||
176 | /* close banks for power saving */ | |
177 | __mxs_clrl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base); | |
178 | ||
179 | once = 1; | |
180 | ||
181 | mutex_unlock(&ocotp_mutex); | |
182 | ||
183 | return ocotp_words; | |
184 | ||
185 | error_unlock: | |
186 | mutex_unlock(&ocotp_mutex); | |
187 | pr_err("%s: timeout in reading OCOTP\n", __func__); | |
188 | return NULL; | |
189 | } | |
190 | ||
5653acc2 SG |
191 | enum mac_oui { |
192 | OUI_FSL, | |
193 | OUI_DENX, | |
8eec4b31 | 194 | OUI_CRYSTALFONTZ, |
5653acc2 SG |
195 | }; |
196 | ||
197 | static void __init update_fec_mac_prop(enum mac_oui oui) | |
198 | { | |
199 | struct device_node *np, *from = NULL; | |
fa7c865a | 200 | struct property *newmac; |
5653acc2 SG |
201 | const u32 *ocotp = mxs_get_ocotp(); |
202 | u8 *macaddr; | |
203 | u32 val; | |
204 | int i; | |
205 | ||
206 | for (i = 0; i < 2; i++) { | |
207 | np = of_find_compatible_node(from, NULL, "fsl,imx28-fec"); | |
208 | if (!np) | |
209 | return; | |
16d47701 | 210 | |
5653acc2 SG |
211 | from = np; |
212 | ||
16d47701 MV |
213 | if (of_get_property(np, "local-mac-address", NULL)) |
214 | continue; | |
215 | ||
5653acc2 SG |
216 | newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); |
217 | if (!newmac) | |
218 | return; | |
219 | newmac->value = newmac + 1; | |
220 | newmac->length = 6; | |
221 | ||
222 | newmac->name = kstrdup("local-mac-address", GFP_KERNEL); | |
223 | if (!newmac->name) { | |
224 | kfree(newmac); | |
225 | return; | |
226 | } | |
227 | ||
228 | /* | |
229 | * OCOTP only stores the last 4 octets for each mac address, | |
230 | * so hard-code OUI here. | |
231 | */ | |
232 | macaddr = newmac->value; | |
233 | switch (oui) { | |
234 | case OUI_FSL: | |
235 | macaddr[0] = 0x00; | |
236 | macaddr[1] = 0x04; | |
237 | macaddr[2] = 0x9f; | |
238 | break; | |
239 | case OUI_DENX: | |
240 | macaddr[0] = 0xc0; | |
241 | macaddr[1] = 0xe5; | |
242 | macaddr[2] = 0x4e; | |
243 | break; | |
8eec4b31 MR |
244 | case OUI_CRYSTALFONTZ: |
245 | macaddr[0] = 0x58; | |
246 | macaddr[1] = 0xb9; | |
247 | macaddr[2] = 0xe1; | |
248 | break; | |
5653acc2 SG |
249 | } |
250 | val = ocotp[i]; | |
251 | macaddr[3] = (val >> 16) & 0xff; | |
252 | macaddr[4] = (val >> 8) & 0xff; | |
253 | macaddr[5] = (val >> 0) & 0xff; | |
254 | ||
79d1c712 | 255 | of_update_property(np, newmac); |
5653acc2 SG |
256 | } |
257 | } | |
258 | ||
8fa62e11 | 259 | static inline void enable_clk_enet_out(void) |
bc3a59c1 | 260 | { |
8fa62e11 | 261 | struct clk *clk = clk_get_sys("enet_out", NULL); |
bc3a59c1 | 262 | |
bc3a59c1 DA |
263 | if (!IS_ERR(clk)) |
264 | clk_prepare_enable(clk); | |
8fa62e11 | 265 | } |
5653acc2 | 266 | |
8fa62e11 MV |
267 | static void __init imx28_evk_init(void) |
268 | { | |
5653acc2 | 269 | update_fec_mac_prop(OUI_FSL); |
ab2815c3 | 270 | |
e317317a | 271 | mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); |
bc3a59c1 DA |
272 | } |
273 | ||
44ffb78f | 274 | static void __init imx28_evk_post_init(void) |
8fa62e11 | 275 | { |
44ffb78f SG |
276 | if (!gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT, |
277 | "flexcan-switch")) { | |
278 | flexcan_pdata[0].transceiver_switch = mx28evk_flexcan0_switch; | |
279 | flexcan_pdata[1].transceiver_switch = mx28evk_flexcan1_switch; | |
280 | } | |
281 | } | |
8fa62e11 | 282 | |
3143bbb4 SG |
283 | static int apx4devkit_phy_fixup(struct phy_device *phy) |
284 | { | |
285 | phy->dev_flags |= MICREL_PHY_50MHZ_CLK; | |
286 | return 0; | |
287 | } | |
288 | ||
289 | static void __init apx4devkit_init(void) | |
290 | { | |
291 | enable_clk_enet_out(); | |
292 | ||
293 | if (IS_BUILTIN(CONFIG_PHYLIB)) | |
510d573f | 294 | phy_register_fixup_for_uid(PHY_ID_KSZ8051, MICREL_PHY_ID_MASK, |
3143bbb4 SG |
295 | apx4devkit_phy_fixup); |
296 | } | |
297 | ||
2c7c2c1d SG |
298 | #define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0) |
299 | #define ENET0_MDIO__GPIO_4_1 MXS_GPIO_NR(4, 1) | |
300 | #define ENET0_RX_EN__GPIO_4_2 MXS_GPIO_NR(4, 2) | |
301 | #define ENET0_RXD0__GPIO_4_3 MXS_GPIO_NR(4, 3) | |
302 | #define ENET0_RXD1__GPIO_4_4 MXS_GPIO_NR(4, 4) | |
303 | #define ENET0_TX_EN__GPIO_4_6 MXS_GPIO_NR(4, 6) | |
304 | #define ENET0_TXD0__GPIO_4_7 MXS_GPIO_NR(4, 7) | |
305 | #define ENET0_TXD1__GPIO_4_8 MXS_GPIO_NR(4, 8) | |
306 | #define ENET_CLK__GPIO_4_16 MXS_GPIO_NR(4, 16) | |
307 | ||
308 | #define TX28_FEC_PHY_POWER MXS_GPIO_NR(3, 29) | |
309 | #define TX28_FEC_PHY_RESET MXS_GPIO_NR(4, 13) | |
310 | #define TX28_FEC_nINT MXS_GPIO_NR(4, 5) | |
311 | ||
312 | static const struct gpio tx28_gpios[] __initconst = { | |
313 | { ENET0_MDC__GPIO_4_0, GPIOF_OUT_INIT_LOW, "GPIO_4_0" }, | |
314 | { ENET0_MDIO__GPIO_4_1, GPIOF_OUT_INIT_LOW, "GPIO_4_1" }, | |
315 | { ENET0_RX_EN__GPIO_4_2, GPIOF_OUT_INIT_LOW, "GPIO_4_2" }, | |
316 | { ENET0_RXD0__GPIO_4_3, GPIOF_OUT_INIT_LOW, "GPIO_4_3" }, | |
317 | { ENET0_RXD1__GPIO_4_4, GPIOF_OUT_INIT_LOW, "GPIO_4_4" }, | |
318 | { ENET0_TX_EN__GPIO_4_6, GPIOF_OUT_INIT_LOW, "GPIO_4_6" }, | |
319 | { ENET0_TXD0__GPIO_4_7, GPIOF_OUT_INIT_LOW, "GPIO_4_7" }, | |
320 | { ENET0_TXD1__GPIO_4_8, GPIOF_OUT_INIT_LOW, "GPIO_4_8" }, | |
321 | { ENET_CLK__GPIO_4_16, GPIOF_OUT_INIT_LOW, "GPIO_4_16" }, | |
322 | { TX28_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" }, | |
323 | { TX28_FEC_PHY_RESET, GPIOF_OUT_INIT_LOW, "fec-phy-reset" }, | |
324 | { TX28_FEC_nINT, GPIOF_DIR_IN, "fec-int" }, | |
325 | }; | |
326 | ||
327 | static void __init tx28_post_init(void) | |
328 | { | |
329 | struct device_node *np; | |
330 | struct platform_device *pdev; | |
331 | struct pinctrl *pctl; | |
332 | int ret; | |
333 | ||
334 | enable_clk_enet_out(); | |
335 | ||
336 | np = of_find_compatible_node(NULL, NULL, "fsl,imx28-fec"); | |
337 | pdev = of_find_device_by_node(np); | |
338 | if (!pdev) { | |
339 | pr_err("%s: failed to find fec device\n", __func__); | |
340 | return; | |
341 | } | |
342 | ||
343 | pctl = pinctrl_get_select(&pdev->dev, "gpio_mode"); | |
344 | if (IS_ERR(pctl)) { | |
345 | pr_err("%s: failed to get pinctrl state\n", __func__); | |
346 | return; | |
347 | } | |
348 | ||
349 | ret = gpio_request_array(tx28_gpios, ARRAY_SIZE(tx28_gpios)); | |
350 | if (ret) { | |
351 | pr_err("%s: failed to request gpios: %d\n", __func__, ret); | |
352 | return; | |
353 | } | |
354 | ||
355 | /* Power up fec phy */ | |
356 | gpio_set_value(TX28_FEC_PHY_POWER, 1); | |
357 | msleep(26); /* 25ms according to data sheet */ | |
358 | ||
359 | /* Mode strap pins */ | |
360 | gpio_set_value(ENET0_RX_EN__GPIO_4_2, 1); | |
361 | gpio_set_value(ENET0_RXD0__GPIO_4_3, 1); | |
362 | gpio_set_value(ENET0_RXD1__GPIO_4_4, 1); | |
363 | ||
364 | udelay(100); /* minimum assertion time for nRST */ | |
365 | ||
366 | /* Deasserting FEC PHY RESET */ | |
367 | gpio_set_value(TX28_FEC_PHY_RESET, 1); | |
368 | ||
369 | pinctrl_put(pctl); | |
370 | } | |
371 | ||
ed138c36 | 372 | static void __init crystalfontz_init(void) |
8eec4b31 | 373 | { |
8eec4b31 MR |
374 | update_fec_mac_prop(OUI_CRYSTALFONTZ); |
375 | } | |
376 | ||
2046338d | 377 | static const char __init *mxs_get_soc_id(void) |
e0f7d905 | 378 | { |
2046338d FE |
379 | struct device_node *np; |
380 | void __iomem *digctl_base; | |
381 | ||
382 | np = of_find_compatible_node(NULL, NULL, "fsl,imx23-digctl"); | |
383 | digctl_base = of_iomap(np, 0); | |
384 | WARN_ON(!digctl_base); | |
385 | ||
386 | chipid = readl(digctl_base + HW_DIGCTL_CHIPID); | |
387 | socid = chipid & HW_DIGCTL_CHIPID_MASK; | |
388 | ||
389 | iounmap(digctl_base); | |
390 | of_node_put(np); | |
391 | ||
392 | switch (socid) { | |
393 | case HW_DIGCTL_CHIPID_MX23: | |
394 | return "i.MX23"; | |
395 | case HW_DIGCTL_CHIPID_MX28: | |
396 | return "i.MX28"; | |
397 | default: | |
398 | return "Unknown"; | |
399 | } | |
400 | } | |
401 | ||
402 | static u32 __init mxs_get_cpu_rev(void) | |
403 | { | |
404 | u32 rev = chipid & HW_DIGCTL_REV_MASK; | |
405 | ||
406 | switch (socid) { | |
407 | case HW_DIGCTL_CHIPID_MX23: | |
408 | switch (rev) { | |
409 | case 0x0: | |
410 | return MXS_CHIP_REVISION_1_0; | |
411 | case 0x1: | |
412 | return MXS_CHIP_REVISION_1_1; | |
413 | case 0x2: | |
414 | return MXS_CHIP_REVISION_1_2; | |
415 | case 0x3: | |
416 | return MXS_CHIP_REVISION_1_3; | |
417 | case 0x4: | |
418 | return MXS_CHIP_REVISION_1_4; | |
419 | default: | |
420 | return MXS_CHIP_REV_UNKNOWN; | |
421 | } | |
422 | case HW_DIGCTL_CHIPID_MX28: | |
423 | switch (rev) { | |
424 | case 0x0: | |
425 | return MXS_CHIP_REVISION_1_1; | |
426 | case 0x1: | |
427 | return MXS_CHIP_REVISION_1_2; | |
428 | default: | |
429 | return MXS_CHIP_REV_UNKNOWN; | |
430 | } | |
431 | default: | |
432 | return MXS_CHIP_REV_UNKNOWN; | |
433 | } | |
434 | } | |
435 | ||
436 | static const char __init *mxs_get_revision(void) | |
437 | { | |
438 | u32 rev = mxs_get_cpu_rev(); | |
439 | ||
440 | if (rev != MXS_CHIP_REV_UNKNOWN) | |
441 | return kasprintf(GFP_KERNEL, "TO%d.%d", (rev >> 4) & 0xf, | |
442 | rev & 0xf); | |
443 | else | |
444 | return kasprintf(GFP_KERNEL, "%s", "Unknown"); | |
e0f7d905 MR |
445 | } |
446 | ||
bc3a59c1 DA |
447 | static void __init mxs_machine_init(void) |
448 | { | |
2046338d FE |
449 | struct device_node *root; |
450 | struct device *parent; | |
451 | struct soc_device *soc_dev; | |
452 | struct soc_device_attribute *soc_dev_attr; | |
453 | int ret; | |
454 | ||
455 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | |
456 | if (!soc_dev_attr) | |
457 | return; | |
458 | ||
459 | root = of_find_node_by_path("/"); | |
460 | ret = of_property_read_string(root, "model", &soc_dev_attr->machine); | |
461 | if (ret) | |
462 | return; | |
463 | ||
464 | soc_dev_attr->family = "Freescale MXS Family"; | |
465 | soc_dev_attr->soc_id = mxs_get_soc_id(); | |
466 | soc_dev_attr->revision = mxs_get_revision(); | |
467 | ||
468 | soc_dev = soc_device_register(soc_dev_attr); | |
469 | if (IS_ERR(soc_dev)) { | |
470 | kfree(soc_dev_attr->revision); | |
471 | kfree(soc_dev_attr); | |
472 | return; | |
473 | } | |
474 | ||
475 | parent = soc_device_to_device(soc_dev); | |
476 | ||
bc3a59c1 DA |
477 | if (of_machine_is_compatible("fsl,imx28-evk")) |
478 | imx28_evk_init(); | |
3143bbb4 SG |
479 | else if (of_machine_is_compatible("bluegiga,apx4devkit")) |
480 | apx4devkit_init(); | |
ed138c36 BL |
481 | else if (of_machine_is_compatible("crystalfontz,cfa10037") || |
482 | of_machine_is_compatible("crystalfontz,cfa10049") || | |
d75f3d92 BL |
483 | of_machine_is_compatible("crystalfontz,cfa10055") || |
484 | of_machine_is_compatible("crystalfontz,cfa10057")) | |
ed138c36 | 485 | crystalfontz_init(); |
bc3a59c1 DA |
486 | |
487 | of_platform_populate(NULL, of_default_bus_match_table, | |
2046338d | 488 | mxs_auxdata_lookup, parent); |
2c7c2c1d SG |
489 | |
490 | if (of_machine_is_compatible("karo,tx28")) | |
491 | tx28_post_init(); | |
44ffb78f SG |
492 | |
493 | if (of_machine_is_compatible("fsl,imx28-evk")) | |
494 | imx28_evk_post_init(); | |
bc3a59c1 DA |
495 | } |
496 | ||
974a9af5 SG |
497 | #define MX23_CLKCTRL_RESET_OFFSET 0x120 |
498 | #define MX28_CLKCTRL_RESET_OFFSET 0x1e0 | |
499 | #define MXS_CLKCTRL_RESET_CHIP (1 << 1) | |
500 | ||
501 | /* | |
502 | * Reset the system. It is called by machine_restart(). | |
503 | */ | |
7b6d864b | 504 | static void mxs_restart(enum reboot_mode mode, const char *cmd) |
974a9af5 SG |
505 | { |
506 | struct device_node *np; | |
507 | void __iomem *reset_addr; | |
508 | ||
509 | np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); | |
510 | reset_addr = of_iomap(np, 0); | |
511 | if (!reset_addr) | |
512 | goto soft; | |
513 | ||
514 | if (of_device_is_compatible(np, "fsl,imx23-clkctrl")) | |
515 | reset_addr += MX23_CLKCTRL_RESET_OFFSET; | |
516 | else | |
517 | reset_addr += MX28_CLKCTRL_RESET_OFFSET; | |
518 | ||
519 | /* reset the chip */ | |
520 | __mxs_setl(MXS_CLKCTRL_RESET_CHIP, reset_addr); | |
521 | ||
522 | pr_err("Failed to assert the chip reset\n"); | |
523 | ||
524 | /* Delay to allow the serial port to show the message */ | |
525 | mdelay(50); | |
526 | ||
527 | soft: | |
528 | /* We'll take a jump through zero as a poor second */ | |
529 | soft_restart(0); | |
530 | } | |
531 | ||
39490ab0 SG |
532 | static void __init mxs_timer_init(void) |
533 | { | |
534 | if (of_machine_is_compatible("fsl,imx23")) | |
535 | mx23_clocks_init(); | |
536 | else | |
537 | mx28_clocks_init(); | |
538 | clocksource_of_init(); | |
539 | } | |
2954ff39 | 540 | |
39490ab0 | 541 | static const char *mxs_dt_compat[] __initdata = { |
bc3a59c1 | 542 | "fsl,imx28", |
39490ab0 | 543 | "fsl,imx23", |
bc3a59c1 DA |
544 | NULL, |
545 | }; | |
546 | ||
39490ab0 | 547 | DT_MACHINE_START(MXS, "Freescale MXS (Device Tree)") |
4e0a1b8c | 548 | .handle_irq = icoll_handle_irq, |
39490ab0 | 549 | .init_time = mxs_timer_init, |
bc3a59c1 | 550 | .init_machine = mxs_machine_init, |
45680995 | 551 | .init_late = mxs_pm_init, |
39490ab0 | 552 | .dt_compat = mxs_dt_compat, |
bc3a59c1 DA |
553 | .restart = mxs_restart, |
554 | MACHINE_END |