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