]>
Commit | Line | Data |
---|---|---|
89d63fe1 | 1 | /* |
89d63fe1 AN |
2 | * Based on linux/arch/mips/txx9/rbtx4938/setup.c, |
3 | * and RBTX49xx patch from CELF patch archive. | |
4 | * | |
5 | * 2003-2005 (c) MontaVista Software, Inc. | |
6 | * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 | |
7 | * | |
8 | * This file is subject to the terms and conditions of the GNU General Public | |
9 | * License. See the file "COPYING" in the main directory of this archive | |
10 | * for more details. | |
11 | */ | |
12 | #include <linux/init.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/types.h> | |
edcaf1a6 AN |
15 | #include <linux/interrupt.h> |
16 | #include <linux/string.h> | |
26dd3e4f | 17 | #include <linux/export.h> |
44ce9a9a GU |
18 | #include <linux/clk-provider.h> |
19 | #include <linux/clkdev.h> | |
edcaf1a6 | 20 | #include <linux/err.h> |
be7658f7 | 21 | #include <linux/gpio/driver.h> |
68314725 | 22 | #include <linux/platform_device.h> |
7779a5e0 | 23 | #include <linux/serial_core.h> |
51f607c7 | 24 | #include <linux/mtd/physmap.h> |
ae027ead | 25 | #include <linux/leds.h> |
269a3eb1 | 26 | #include <linux/device.h> |
5a0e3ad6 | 27 | #include <linux/slab.h> |
ca4d3e67 | 28 | #include <linux/irq.h> |
edcaf1a6 | 29 | #include <asm/bootinfo.h> |
bdc92d74 | 30 | #include <asm/idle.h> |
e0eb7307 | 31 | #include <asm/time.h> |
a49297e8 | 32 | #include <asm/reboot.h> |
d10e025f | 33 | #include <asm/r4kcache.h> |
b6263ff2 | 34 | #include <asm/sections.h> |
89d63fe1 | 35 | #include <asm/txx9/generic.h> |
07517529 | 36 | #include <asm/txx9/pci.h> |
496a3b5c | 37 | #include <asm/txx9tmr.h> |
a591f5d3 | 38 | #include <asm/txx9/ndfmc.h> |
f48c8c95 | 39 | #include <asm/txx9/dmac.h> |
edcaf1a6 AN |
40 | #ifdef CONFIG_CPU_TX49XX |
41 | #include <asm/txx9/tx4938.h> | |
42 | #endif | |
89d63fe1 AN |
43 | |
44 | /* EBUSC settings of TX4927, etc. */ | |
45 | struct resource txx9_ce_res[8]; | |
46 | static char txx9_ce_res_name[8][4]; /* "CEn" */ | |
47 | ||
48 | /* pcode, internal register */ | |
94a4c329 | 49 | unsigned int txx9_pcode; |
89d63fe1 AN |
50 | char txx9_pcode_str[8]; |
51 | static struct resource txx9_reg_res = { | |
52 | .name = txx9_pcode_str, | |
53 | .flags = IORESOURCE_MEM, | |
54 | }; | |
55 | void __init | |
56 | txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size) | |
57 | { | |
58 | int i; | |
59 | ||
60 | for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) { | |
61 | sprintf(txx9_ce_res_name[i], "CE%d", i); | |
62 | txx9_ce_res[i].flags = IORESOURCE_MEM; | |
63 | txx9_ce_res[i].name = txx9_ce_res_name[i]; | |
64 | } | |
65 | ||
073828d0 | 66 | txx9_pcode = pcode; |
89d63fe1 AN |
67 | sprintf(txx9_pcode_str, "TX%x", pcode); |
68 | if (base) { | |
69 | txx9_reg_res.start = base & 0xfffffffffULL; | |
70 | txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1); | |
71 | request_resource(&iomem_resource, &txx9_reg_res); | |
72 | } | |
73 | } | |
74 | ||
75 | /* clocks */ | |
76 | unsigned int txx9_master_clock; | |
77 | unsigned int txx9_cpu_clock; | |
78 | unsigned int txx9_gbus_clock; | |
edcaf1a6 | 79 | |
c7b95bcb AN |
80 | #ifdef CONFIG_CPU_TX39XX |
81 | /* don't enable by default - see errata */ | |
82 | int txx9_ccfg_toeon __initdata; | |
83 | #else | |
94a4c329 | 84 | int txx9_ccfg_toeon __initdata = 1; |
c7b95bcb | 85 | #endif |
edcaf1a6 | 86 | |
860e546c AN |
87 | #define BOARD_VEC(board) extern struct txx9_board_vec board; |
88 | #include <asm/txx9/boards.h> | |
89 | #undef BOARD_VEC | |
edcaf1a6 | 90 | |
edcaf1a6 AN |
91 | struct txx9_board_vec *txx9_board_vec __initdata; |
92 | static char txx9_system_type[32]; | |
93 | ||
860e546c AN |
94 | static struct txx9_board_vec *board_vecs[] __initdata = { |
95 | #define BOARD_VEC(board) &board, | |
96 | #include <asm/txx9/boards.h> | |
97 | #undef BOARD_VEC | |
98 | }; | |
99 | ||
100 | static struct txx9_board_vec *__init find_board_byname(const char *name) | |
101 | { | |
102 | int i; | |
103 | ||
104 | /* search board_vecs table */ | |
105 | for (i = 0; i < ARRAY_SIZE(board_vecs); i++) { | |
106 | if (strstr(board_vecs[i]->system, name)) | |
107 | return board_vecs[i]; | |
108 | } | |
109 | return NULL; | |
110 | } | |
111 | ||
e0dfb20c | 112 | static void __init prom_init_cmdline(void) |
edcaf1a6 | 113 | { |
97b0511c GU |
114 | int argc; |
115 | int *argv32; | |
edcaf1a6 AN |
116 | int i; /* Always ignore the "-c" at argv[0] */ |
117 | ||
97b0511c GU |
118 | if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) { |
119 | /* | |
120 | * argc is not a valid number, or argv32 is not a valid | |
121 | * pointer | |
122 | */ | |
123 | argc = 0; | |
124 | argv32 = NULL; | |
125 | } else { | |
126 | argc = (int)fw_arg0; | |
127 | argv32 = (int *)fw_arg1; | |
128 | } | |
129 | ||
e0dfb20c | 130 | arcs_cmdline[0] = '\0'; |
edcaf1a6 AN |
131 | |
132 | for (i = 1; i < argc; i++) { | |
e0dfb20c | 133 | char *str = (char *)(long)argv32[i]; |
edcaf1a6 AN |
134 | if (i != 1) |
135 | strcat(arcs_cmdline, " "); | |
e0dfb20c AN |
136 | if (strchr(str, ' ')) { |
137 | strcat(arcs_cmdline, "\""); | |
138 | strcat(arcs_cmdline, str); | |
139 | strcat(arcs_cmdline, "\""); | |
140 | } else | |
141 | strcat(arcs_cmdline, str); | |
142 | } | |
edcaf1a6 AN |
143 | } |
144 | ||
d10e025f AN |
145 | static int txx9_ic_disable __initdata; |
146 | static int txx9_dc_disable __initdata; | |
147 | ||
148 | #if defined(CONFIG_CPU_TX49XX) | |
149 | /* flush all cache on very early stage (before 4k_cache_init) */ | |
150 | static void __init early_flush_dcache(void) | |
151 | { | |
152 | unsigned int conf = read_c0_config(); | |
153 | unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6)); | |
154 | unsigned int linesz = 32; | |
155 | unsigned long addr, end; | |
156 | ||
157 | end = INDEX_BASE + dc_size / 4; | |
158 | /* 4way, waybit=0 */ | |
159 | for (addr = INDEX_BASE; addr < end; addr += linesz) { | |
160 | cache_op(Index_Writeback_Inv_D, addr | 0); | |
161 | cache_op(Index_Writeback_Inv_D, addr | 1); | |
162 | cache_op(Index_Writeback_Inv_D, addr | 2); | |
163 | cache_op(Index_Writeback_Inv_D, addr | 3); | |
164 | } | |
165 | } | |
166 | ||
167 | static void __init txx9_cache_fixup(void) | |
168 | { | |
169 | unsigned int conf; | |
170 | ||
171 | conf = read_c0_config(); | |
172 | /* flush and disable */ | |
173 | if (txx9_ic_disable) { | |
174 | conf |= TX49_CONF_IC; | |
175 | write_c0_config(conf); | |
176 | } | |
177 | if (txx9_dc_disable) { | |
178 | early_flush_dcache(); | |
179 | conf |= TX49_CONF_DC; | |
180 | write_c0_config(conf); | |
181 | } | |
182 | ||
183 | /* enable cache */ | |
184 | conf = read_c0_config(); | |
185 | if (!txx9_ic_disable) | |
186 | conf &= ~TX49_CONF_IC; | |
187 | if (!txx9_dc_disable) | |
188 | conf &= ~TX49_CONF_DC; | |
189 | write_c0_config(conf); | |
190 | ||
191 | if (conf & TX49_CONF_IC) | |
192 | pr_info("TX49XX I-Cache disabled.\n"); | |
193 | if (conf & TX49_CONF_DC) | |
194 | pr_info("TX49XX D-Cache disabled.\n"); | |
195 | } | |
196 | #elif defined(CONFIG_CPU_TX39XX) | |
197 | /* flush all cache on very early stage (before tx39_cache_init) */ | |
198 | static void __init early_flush_dcache(void) | |
199 | { | |
200 | unsigned int conf = read_c0_config(); | |
201 | unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >> | |
202 | TX39_CONF_DCS_SHIFT)); | |
203 | unsigned int linesz = 16; | |
204 | unsigned long addr, end; | |
205 | ||
206 | end = INDEX_BASE + dc_size / 2; | |
207 | /* 2way, waybit=0 */ | |
208 | for (addr = INDEX_BASE; addr < end; addr += linesz) { | |
209 | cache_op(Index_Writeback_Inv_D, addr | 0); | |
210 | cache_op(Index_Writeback_Inv_D, addr | 1); | |
211 | } | |
212 | } | |
213 | ||
214 | static void __init txx9_cache_fixup(void) | |
215 | { | |
216 | unsigned int conf; | |
217 | ||
218 | conf = read_c0_config(); | |
219 | /* flush and disable */ | |
220 | if (txx9_ic_disable) { | |
221 | conf &= ~TX39_CONF_ICE; | |
222 | write_c0_config(conf); | |
223 | } | |
224 | if (txx9_dc_disable) { | |
225 | early_flush_dcache(); | |
226 | conf &= ~TX39_CONF_DCE; | |
227 | write_c0_config(conf); | |
228 | } | |
229 | ||
230 | /* enable cache */ | |
231 | conf = read_c0_config(); | |
232 | if (!txx9_ic_disable) | |
233 | conf |= TX39_CONF_ICE; | |
234 | if (!txx9_dc_disable) | |
235 | conf |= TX39_CONF_DCE; | |
236 | write_c0_config(conf); | |
237 | ||
238 | if (!(conf & TX39_CONF_ICE)) | |
239 | pr_info("TX39XX I-Cache disabled.\n"); | |
240 | if (!(conf & TX39_CONF_DCE)) | |
241 | pr_info("TX39XX D-Cache disabled.\n"); | |
242 | } | |
243 | #else | |
244 | static inline void txx9_cache_fixup(void) | |
245 | { | |
246 | } | |
247 | #endif | |
248 | ||
860e546c | 249 | static void __init preprocess_cmdline(void) |
edcaf1a6 | 250 | { |
7580c9c3 | 251 | static char cmdline[COMMAND_LINE_SIZE] __initdata; |
860e546c AN |
252 | char *s; |
253 | ||
254 | strcpy(cmdline, arcs_cmdline); | |
255 | s = cmdline; | |
256 | arcs_cmdline[0] = '\0'; | |
257 | while (s && *s) { | |
258 | char *str = strsep(&s, " "); | |
259 | if (strncmp(str, "board=", 6) == 0) { | |
260 | txx9_board_vec = find_board_byname(str + 6); | |
261 | continue; | |
262 | } else if (strncmp(str, "masterclk=", 10) == 0) { | |
8e9ecbc5 DW |
263 | unsigned int val; |
264 | if (kstrtouint(str + 10, 10, &val) == 0) | |
860e546c AN |
265 | txx9_master_clock = val; |
266 | continue; | |
d10e025f AN |
267 | } else if (strcmp(str, "icdisable") == 0) { |
268 | txx9_ic_disable = 1; | |
269 | continue; | |
270 | } else if (strcmp(str, "dcdisable") == 0) { | |
271 | txx9_dc_disable = 1; | |
272 | continue; | |
c7b95bcb AN |
273 | } else if (strcmp(str, "toeoff") == 0) { |
274 | txx9_ccfg_toeon = 0; | |
275 | continue; | |
276 | } else if (strcmp(str, "toeon") == 0) { | |
277 | txx9_ccfg_toeon = 1; | |
278 | continue; | |
860e546c AN |
279 | } |
280 | if (arcs_cmdline[0]) | |
281 | strcat(arcs_cmdline, " "); | |
282 | strcat(arcs_cmdline, str); | |
283 | } | |
d10e025f AN |
284 | |
285 | txx9_cache_fixup(); | |
860e546c AN |
286 | } |
287 | ||
288 | static void __init select_board(void) | |
289 | { | |
290 | const char *envstr; | |
291 | ||
292 | /* first, determine by "board=" argument in preprocess_cmdline() */ | |
293 | if (txx9_board_vec) | |
294 | return; | |
295 | /* next, determine by "board" envvar */ | |
296 | envstr = prom_getenv("board"); | |
297 | if (envstr) { | |
298 | txx9_board_vec = find_board_byname(envstr); | |
299 | if (txx9_board_vec) | |
300 | return; | |
301 | } | |
302 | ||
303 | /* select "default" board */ | |
c8acd40d | 304 | #ifdef CONFIG_TOSHIBA_JMR3927 |
7a1fdf19 | 305 | txx9_board_vec = &jmr3927_vec; |
edcaf1a6 AN |
306 | #endif |
307 | #ifdef CONFIG_CPU_TX49XX | |
308 | switch (TX4938_REV_PCODE()) { | |
8d795f2a | 309 | #ifdef CONFIG_TOSHIBA_RBTX4927 |
edcaf1a6 | 310 | case 0x4927: |
7a1fdf19 | 311 | txx9_board_vec = &rbtx4927_vec; |
edcaf1a6 AN |
312 | break; |
313 | case 0x4937: | |
7a1fdf19 | 314 | txx9_board_vec = &rbtx4937_vec; |
edcaf1a6 | 315 | break; |
8d795f2a AN |
316 | #endif |
317 | #ifdef CONFIG_TOSHIBA_RBTX4938 | |
edcaf1a6 | 318 | case 0x4938: |
7a1fdf19 | 319 | txx9_board_vec = &rbtx4938_vec; |
edcaf1a6 | 320 | break; |
b27311e1 AN |
321 | #endif |
322 | #ifdef CONFIG_TOSHIBA_RBTX4939 | |
323 | case 0x4939: | |
324 | txx9_board_vec = &rbtx4939_vec; | |
325 | break; | |
8d795f2a | 326 | #endif |
edcaf1a6 AN |
327 | } |
328 | #endif | |
860e546c AN |
329 | } |
330 | ||
331 | void __init prom_init(void) | |
332 | { | |
333 | prom_init_cmdline(); | |
334 | preprocess_cmdline(); | |
335 | select_board(); | |
7a1fdf19 YY |
336 | |
337 | strcpy(txx9_system_type, txx9_board_vec->system); | |
338 | ||
7b226094 | 339 | txx9_board_vec->prom_init(); |
edcaf1a6 AN |
340 | } |
341 | ||
342 | void __init prom_free_prom_memory(void) | |
343 | { | |
b6263ff2 AN |
344 | unsigned long saddr = PAGE_SIZE; |
345 | unsigned long eaddr = __pa_symbol(&_text); | |
346 | ||
347 | if (saddr < eaddr) | |
348 | free_init_pages("prom memory", saddr, eaddr); | |
edcaf1a6 AN |
349 | } |
350 | ||
351 | const char *get_system_type(void) | |
352 | { | |
353 | return txx9_system_type; | |
354 | } | |
355 | ||
265b89db AN |
356 | const char *__init prom_getenv(const char *name) |
357 | { | |
97b0511c | 358 | const s32 *str; |
265b89db | 359 | |
97b0511c | 360 | if (fw_arg2 < CKSEG0) |
265b89db | 361 | return NULL; |
97b0511c GU |
362 | |
363 | str = (const s32 *)fw_arg2; | |
265b89db AN |
364 | /* YAMON style ("name", "value" pairs) */ |
365 | while (str[0] && str[1]) { | |
366 | if (!strcmp((const char *)(unsigned long)str[0], name)) | |
367 | return (const char *)(unsigned long)str[1]; | |
368 | str += 2; | |
369 | } | |
370 | return NULL; | |
371 | } | |
372 | ||
a49297e8 AN |
373 | static void __noreturn txx9_machine_halt(void) |
374 | { | |
375 | local_irq_disable(); | |
376 | clear_c0_status(ST0_IM); | |
377 | while (1) { | |
378 | if (cpu_wait) { | |
379 | (*cpu_wait)(); | |
380 | if (cpu_has_counter) { | |
381 | /* | |
382 | * Clear counter interrupt while it | |
383 | * breaks WAIT instruction even if | |
384 | * masked. | |
385 | */ | |
386 | write_c0_compare(0); | |
387 | } | |
388 | } | |
389 | } | |
390 | } | |
391 | ||
68314725 AN |
392 | /* Watchdog support */ |
393 | void __init txx9_wdt_init(unsigned long base) | |
394 | { | |
395 | struct resource res = { | |
396 | .start = base, | |
397 | .end = base + 0x100 - 1, | |
398 | .flags = IORESOURCE_MEM, | |
399 | }; | |
400 | platform_device_register_simple("txx9wdt", -1, &res, 1); | |
401 | } | |
402 | ||
496a3b5c AN |
403 | void txx9_wdt_now(unsigned long base) |
404 | { | |
405 | struct txx9_tmr_reg __iomem *tmrptr = | |
406 | ioremap(base, sizeof(struct txx9_tmr_reg)); | |
407 | /* disable watch dog timer */ | |
408 | __raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr); | |
409 | __raw_writel(0, &tmrptr->tcr); | |
410 | /* kick watchdog */ | |
411 | __raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr); | |
412 | __raw_writel(1, &tmrptr->cpra); /* immediate */ | |
413 | __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, | |
414 | &tmrptr->tcr); | |
415 | } | |
416 | ||
c49f91f5 AN |
417 | /* SPI support */ |
418 | void __init txx9_spi_init(int busid, unsigned long base, int irq) | |
419 | { | |
420 | struct resource res[] = { | |
421 | { | |
422 | .start = base, | |
423 | .end = base + 0x20 - 1, | |
424 | .flags = IORESOURCE_MEM, | |
425 | }, { | |
426 | .start = irq, | |
427 | .flags = IORESOURCE_IRQ, | |
428 | }, | |
429 | }; | |
430 | platform_device_register_simple("spi_txx9", busid, | |
431 | res, ARRAY_SIZE(res)); | |
432 | } | |
433 | ||
434 | void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr) | |
435 | { | |
436 | struct platform_device *pdev = | |
437 | platform_device_alloc("tc35815-mac", id); | |
438 | if (!pdev || | |
439 | platform_device_add_data(pdev, ethaddr, 6) || | |
440 | platform_device_add(pdev)) | |
441 | platform_device_put(pdev); | |
442 | } | |
443 | ||
7779a5e0 AN |
444 | void __init txx9_sio_init(unsigned long baseaddr, int irq, |
445 | unsigned int line, unsigned int sclk, int nocts) | |
446 | { | |
447 | #ifdef CONFIG_SERIAL_TXX9 | |
448 | struct uart_port req; | |
449 | ||
450 | memset(&req, 0, sizeof(req)); | |
451 | req.line = line; | |
452 | req.iotype = UPIO_MEM; | |
453 | req.membase = ioremap(baseaddr, 0x24); | |
454 | req.mapbase = baseaddr; | |
455 | req.irq = irq; | |
456 | if (!nocts) | |
457 | req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | |
458 | if (sclk) { | |
459 | req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/; | |
460 | req.uartclk = sclk; | |
461 | } else | |
462 | req.uartclk = TXX9_IMCLK; | |
463 | early_serial_txx9_setup(&req); | |
464 | #endif /* CONFIG_SERIAL_TXX9 */ | |
465 | } | |
466 | ||
e352953c | 467 | #ifdef CONFIG_EARLY_PRINTK |
f7be4e75 | 468 | static void null_prom_putchar(char c) |
e352953c AN |
469 | { |
470 | } | |
f7be4e75 | 471 | void (*txx9_prom_putchar)(char c) = null_prom_putchar; |
e352953c | 472 | |
f7be4e75 | 473 | void prom_putchar(char c) |
e352953c AN |
474 | { |
475 | txx9_prom_putchar(c); | |
476 | } | |
477 | ||
478 | static void __iomem *early_txx9_sio_port; | |
479 | ||
f7be4e75 | 480 | static void early_txx9_sio_putchar(char c) |
e352953c AN |
481 | { |
482 | #define TXX9_SICISR 0x0c | |
483 | #define TXX9_SITFIFO 0x1c | |
484 | #define TXX9_SICISR_TXALS 0x00000002 | |
485 | while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) & | |
486 | TXX9_SICISR_TXALS)) | |
487 | ; | |
488 | __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO); | |
489 | } | |
490 | ||
491 | void __init txx9_sio_putchar_init(unsigned long baseaddr) | |
492 | { | |
493 | early_txx9_sio_port = ioremap(baseaddr, 0x24); | |
494 | txx9_prom_putchar = early_txx9_sio_putchar; | |
495 | } | |
496 | #endif /* CONFIG_EARLY_PRINTK */ | |
497 | ||
edcaf1a6 AN |
498 | /* wrappers */ |
499 | void __init plat_mem_setup(void) | |
500 | { | |
94a4c329 AN |
501 | ioport_resource.start = 0; |
502 | ioport_resource.end = ~0UL; /* no limit */ | |
503 | iomem_resource.start = 0; | |
504 | iomem_resource.end = ~0UL; /* no limit */ | |
a49297e8 AN |
505 | |
506 | /* fallback restart/halt routines */ | |
507 | _machine_restart = (void (*)(char *))txx9_machine_halt; | |
508 | _machine_halt = txx9_machine_halt; | |
509 | pm_power_off = txx9_machine_halt; | |
510 | ||
07517529 AN |
511 | #ifdef CONFIG_PCI |
512 | pcibios_plat_setup = txx9_pcibios_setup; | |
513 | #endif | |
edcaf1a6 AN |
514 | txx9_board_vec->mem_setup(); |
515 | } | |
516 | ||
517 | void __init arch_init_irq(void) | |
518 | { | |
519 | txx9_board_vec->irq_setup(); | |
520 | } | |
521 | ||
522 | void __init plat_time_init(void) | |
523 | { | |
1374d084 AN |
524 | #ifdef CONFIG_CPU_TX49XX |
525 | mips_hpt_frequency = txx9_cpu_clock / 2; | |
526 | #endif | |
edcaf1a6 AN |
527 | txx9_board_vec->time_init(); |
528 | } | |
529 | ||
44ce9a9a GU |
530 | static void txx9_clk_init(void) |
531 | { | |
532 | struct clk_hw *hw; | |
533 | int error; | |
534 | ||
535 | hw = clk_hw_register_fixed_rate(NULL, "gbus", NULL, 0, txx9_gbus_clock); | |
536 | if (IS_ERR(hw)) { | |
537 | error = PTR_ERR(hw); | |
538 | goto fail; | |
539 | } | |
540 | ||
541 | hw = clk_hw_register_fixed_factor(NULL, "imbus", "gbus", 0, 1, 2); | |
542 | error = clk_hw_register_clkdev(hw, "imbus_clk", NULL); | |
543 | if (error) | |
544 | goto fail; | |
545 | ||
546 | #ifdef CONFIG_CPU_TX49XX | |
547 | if (TX4938_REV_PCODE() == 0x4938) { | |
548 | hw = clk_hw_register_fixed_factor(NULL, "spi", "gbus", 0, 1, 4); | |
549 | error = clk_hw_register_clkdev(hw, "spi-baseclk", NULL); | |
550 | if (error) | |
551 | goto fail; | |
552 | } | |
553 | #endif | |
554 | ||
555 | return; | |
556 | ||
557 | fail: | |
558 | pr_err("Failed to register clocks: %d\n", error); | |
559 | } | |
560 | ||
edcaf1a6 AN |
561 | static int __init _txx9_arch_init(void) |
562 | { | |
44ce9a9a GU |
563 | txx9_clk_init(); |
564 | ||
edcaf1a6 AN |
565 | if (txx9_board_vec->arch_init) |
566 | txx9_board_vec->arch_init(); | |
567 | return 0; | |
568 | } | |
569 | arch_initcall(_txx9_arch_init); | |
570 | ||
571 | static int __init _txx9_device_init(void) | |
572 | { | |
573 | if (txx9_board_vec->device_init) | |
574 | txx9_board_vec->device_init(); | |
575 | return 0; | |
576 | } | |
577 | device_initcall(_txx9_device_init); | |
578 | ||
579 | int (*txx9_irq_dispatch)(int pending); | |
580 | asmlinkage void plat_irq_dispatch(void) | |
581 | { | |
582 | int pending = read_c0_status() & read_c0_cause() & ST0_IM; | |
583 | int irq = txx9_irq_dispatch(pending); | |
584 | ||
585 | if (likely(irq >= 0)) | |
586 | do_IRQ(irq); | |
587 | else | |
588 | spurious_interrupt(); | |
589 | } | |
4c642f3f AN |
590 | |
591 | /* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */ | |
592 | #ifdef NEEDS_TXX9_SWIZZLE_ADDR_B | |
593 | static unsigned long __swizzle_addr_none(unsigned long port) | |
594 | { | |
595 | return port; | |
596 | } | |
597 | unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none; | |
598 | EXPORT_SYMBOL(__swizzle_addr_b); | |
599 | #endif | |
51f607c7 | 600 | |
1ba5a176 AN |
601 | #ifdef NEEDS_TXX9_IOSWABW |
602 | static u16 ioswabw_default(volatile u16 *a, u16 x) | |
603 | { | |
604 | return le16_to_cpu(x); | |
605 | } | |
606 | static u16 __mem_ioswabw_default(volatile u16 *a, u16 x) | |
607 | { | |
608 | return x; | |
609 | } | |
610 | u16 (*ioswabw)(volatile u16 *a, u16 x) = ioswabw_default; | |
611 | EXPORT_SYMBOL(ioswabw); | |
612 | u16 (*__mem_ioswabw)(volatile u16 *a, u16 x) = __mem_ioswabw_default; | |
613 | EXPORT_SYMBOL(__mem_ioswabw); | |
614 | #endif | |
615 | ||
51f607c7 AN |
616 | void __init txx9_physmap_flash_init(int no, unsigned long addr, |
617 | unsigned long size, | |
618 | const struct physmap_flash_data *pdata) | |
619 | { | |
b33b4407 | 620 | #if IS_ENABLED(CONFIG_MTD_PHYSMAP) |
51f607c7 AN |
621 | struct resource res = { |
622 | .start = addr, | |
623 | .end = addr + size - 1, | |
624 | .flags = IORESOURCE_MEM, | |
625 | }; | |
626 | struct platform_device *pdev; | |
51f607c7 AN |
627 | static struct mtd_partition parts[2]; |
628 | struct physmap_flash_data pdata_part; | |
629 | ||
630 | /* If this area contained boot area, make separate partition */ | |
631 | if (pdata->nr_parts == 0 && !pdata->parts && | |
632 | addr < 0x1fc00000 && addr + size > 0x1fc00000 && | |
633 | !parts[0].name) { | |
634 | parts[0].name = "boot"; | |
635 | parts[0].offset = 0x1fc00000 - addr; | |
636 | parts[0].size = addr + size - 0x1fc00000; | |
637 | parts[1].name = "user"; | |
638 | parts[1].offset = 0; | |
639 | parts[1].size = 0x1fc00000 - addr; | |
640 | pdata_part = *pdata; | |
641 | pdata_part.nr_parts = ARRAY_SIZE(parts); | |
642 | pdata_part.parts = parts; | |
643 | pdata = &pdata_part; | |
644 | } | |
47854888 | 645 | |
51f607c7 AN |
646 | pdev = platform_device_alloc("physmap-flash", no); |
647 | if (!pdev || | |
648 | platform_device_add_resources(pdev, &res, 1) || | |
a591f5d3 AN |
649 | platform_device_add_data(pdev, pdata, sizeof(*pdata)) || |
650 | platform_device_add(pdev)) | |
651 | platform_device_put(pdev); | |
652 | #endif | |
653 | } | |
654 | ||
655 | void __init txx9_ndfmc_init(unsigned long baseaddr, | |
656 | const struct txx9ndfmc_platform_data *pdata) | |
657 | { | |
b33b4407 | 658 | #if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC) |
a591f5d3 AN |
659 | struct resource res = { |
660 | .start = baseaddr, | |
661 | .end = baseaddr + 0x1000 - 1, | |
662 | .flags = IORESOURCE_MEM, | |
663 | }; | |
664 | struct platform_device *pdev = platform_device_alloc("txx9ndfmc", -1); | |
665 | ||
666 | if (!pdev || | |
667 | platform_device_add_resources(pdev, &res, 1) || | |
51f607c7 AN |
668 | platform_device_add_data(pdev, pdata, sizeof(*pdata)) || |
669 | platform_device_add(pdev)) | |
670 | platform_device_put(pdev); | |
671 | #endif | |
672 | } | |
ae027ead | 673 | |
b33b4407 | 674 | #if IS_ENABLED(CONFIG_LEDS_GPIO) |
ae027ead AN |
675 | static DEFINE_SPINLOCK(txx9_iocled_lock); |
676 | ||
677 | #define TXX9_IOCLED_MAXLEDS 8 | |
678 | ||
679 | struct txx9_iocled_data { | |
680 | struct gpio_chip chip; | |
681 | u8 cur_val; | |
682 | void __iomem *mmioaddr; | |
683 | struct gpio_led_platform_data pdata; | |
684 | struct gpio_led leds[TXX9_IOCLED_MAXLEDS]; | |
685 | char names[TXX9_IOCLED_MAXLEDS][32]; | |
686 | }; | |
687 | ||
688 | static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset) | |
689 | { | |
be7658f7 | 690 | struct txx9_iocled_data *data = gpiochip_get_data(chip); |
8cbe4b5c | 691 | return !!(data->cur_val & (1 << offset)); |
ae027ead AN |
692 | } |
693 | ||
694 | static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, | |
695 | int value) | |
696 | { | |
be7658f7 | 697 | struct txx9_iocled_data *data = gpiochip_get_data(chip); |
ae027ead AN |
698 | unsigned long flags; |
699 | spin_lock_irqsave(&txx9_iocled_lock, flags); | |
700 | if (value) | |
701 | data->cur_val |= 1 << offset; | |
702 | else | |
703 | data->cur_val &= ~(1 << offset); | |
704 | writeb(data->cur_val, data->mmioaddr); | |
705 | mmiowb(); | |
706 | spin_unlock_irqrestore(&txx9_iocled_lock, flags); | |
707 | } | |
708 | ||
709 | static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset) | |
710 | { | |
711 | return 0; | |
712 | } | |
713 | ||
714 | static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset, | |
715 | int value) | |
716 | { | |
717 | txx9_iocled_set(chip, offset, value); | |
718 | return 0; | |
719 | } | |
720 | ||
721 | void __init txx9_iocled_init(unsigned long baseaddr, | |
722 | int basenum, unsigned int num, int lowactive, | |
723 | const char *color, char **deftriggers) | |
724 | { | |
725 | struct txx9_iocled_data *iocled; | |
726 | struct platform_device *pdev; | |
727 | int i; | |
728 | static char *default_triggers[] __initdata = { | |
729 | "heartbeat", | |
dde00512 | 730 | "disk-activity", |
ae027ead AN |
731 | "nand-disk", |
732 | NULL, | |
733 | }; | |
734 | ||
735 | if (!deftriggers) | |
736 | deftriggers = default_triggers; | |
737 | iocled = kzalloc(sizeof(*iocled), GFP_KERNEL); | |
738 | if (!iocled) | |
739 | return; | |
740 | iocled->mmioaddr = ioremap(baseaddr, 1); | |
741 | if (!iocled->mmioaddr) | |
70ebadc8 | 742 | goto out_free; |
ae027ead AN |
743 | iocled->chip.get = txx9_iocled_get; |
744 | iocled->chip.set = txx9_iocled_set; | |
745 | iocled->chip.direction_input = txx9_iocled_dir_in; | |
746 | iocled->chip.direction_output = txx9_iocled_dir_out; | |
747 | iocled->chip.label = "iocled"; | |
748 | iocled->chip.base = basenum; | |
749 | iocled->chip.ngpio = num; | |
be7658f7 | 750 | if (gpiochip_add_data(&iocled->chip, iocled)) |
70ebadc8 | 751 | goto out_unmap; |
ae027ead AN |
752 | if (basenum < 0) |
753 | basenum = iocled->chip.base; | |
754 | ||
755 | pdev = platform_device_alloc("leds-gpio", basenum); | |
756 | if (!pdev) | |
70ebadc8 | 757 | goto out_gpio; |
ae027ead AN |
758 | iocled->pdata.num_leds = num; |
759 | iocled->pdata.leds = iocled->leds; | |
760 | for (i = 0; i < num; i++) { | |
761 | struct gpio_led *led = &iocled->leds[i]; | |
762 | snprintf(iocled->names[i], sizeof(iocled->names[i]), | |
763 | "iocled:%s:%u", color, i); | |
764 | led->name = iocled->names[i]; | |
765 | led->gpio = basenum + i; | |
766 | led->active_low = lowactive; | |
767 | if (deftriggers && *deftriggers) | |
768 | led->default_trigger = *deftriggers++; | |
769 | } | |
770 | pdev->dev.platform_data = &iocled->pdata; | |
771 | if (platform_device_add(pdev)) | |
70ebadc8 JL |
772 | goto out_pdev; |
773 | return; | |
88d5e520 | 774 | |
70ebadc8 JL |
775 | out_pdev: |
776 | platform_device_put(pdev); | |
777 | out_gpio: | |
88d5e520 | 778 | gpiochip_remove(&iocled->chip); |
70ebadc8 JL |
779 | out_unmap: |
780 | iounmap(iocled->mmioaddr); | |
781 | out_free: | |
782 | kfree(iocled); | |
ae027ead AN |
783 | } |
784 | #else /* CONFIG_LEDS_GPIO */ | |
785 | void __init txx9_iocled_init(unsigned long baseaddr, | |
786 | int basenum, unsigned int num, int lowactive, | |
787 | const char *color, char **deftriggers) | |
788 | { | |
789 | } | |
790 | #endif /* CONFIG_LEDS_GPIO */ | |
f48c8c95 AN |
791 | |
792 | void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq, | |
793 | const struct txx9dmac_platform_data *pdata) | |
794 | { | |
b33b4407 | 795 | #if IS_ENABLED(CONFIG_TXX9_DMAC) |
f48c8c95 AN |
796 | struct resource res[] = { |
797 | { | |
798 | .start = baseaddr, | |
799 | .end = baseaddr + 0x800 - 1, | |
800 | .flags = IORESOURCE_MEM, | |
801 | #ifndef CONFIG_MACH_TX49XX | |
802 | }, { | |
803 | .start = irq, | |
804 | .flags = IORESOURCE_IRQ, | |
805 | #endif | |
806 | } | |
807 | }; | |
808 | #ifdef CONFIG_MACH_TX49XX | |
809 | struct resource chan_res[] = { | |
810 | { | |
811 | .flags = IORESOURCE_IRQ, | |
812 | } | |
813 | }; | |
814 | #endif | |
815 | struct platform_device *pdev = platform_device_alloc("txx9dmac", id); | |
816 | struct txx9dmac_chan_platform_data cpdata; | |
817 | int i; | |
818 | ||
819 | if (!pdev || | |
820 | platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) || | |
821 | platform_device_add_data(pdev, pdata, sizeof(*pdata)) || | |
822 | platform_device_add(pdev)) { | |
823 | platform_device_put(pdev); | |
824 | return; | |
825 | } | |
826 | memset(&cpdata, 0, sizeof(cpdata)); | |
827 | cpdata.dmac_dev = pdev; | |
828 | for (i = 0; i < TXX9_DMA_MAX_NR_CHANNELS; i++) { | |
829 | #ifdef CONFIG_MACH_TX49XX | |
830 | chan_res[0].start = irq + i; | |
831 | #endif | |
832 | pdev = platform_device_alloc("txx9dmac-chan", | |
833 | id * TXX9_DMA_MAX_NR_CHANNELS + i); | |
834 | if (!pdev || | |
835 | #ifdef CONFIG_MACH_TX49XX | |
836 | platform_device_add_resources(pdev, chan_res, | |
837 | ARRAY_SIZE(chan_res)) || | |
838 | #endif | |
839 | platform_device_add_data(pdev, &cpdata, sizeof(cpdata)) || | |
840 | platform_device_add(pdev)) | |
841 | platform_device_put(pdev); | |
842 | } | |
843 | #endif | |
844 | } | |
742cd586 AN |
845 | |
846 | void __init txx9_aclc_init(unsigned long baseaddr, int irq, | |
847 | unsigned int dmac_id, | |
848 | unsigned int dma_chan_out, | |
849 | unsigned int dma_chan_in) | |
850 | { | |
b33b4407 | 851 | #if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC) |
742cd586 AN |
852 | unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS; |
853 | struct resource res[] = { | |
854 | { | |
855 | .start = baseaddr, | |
856 | .end = baseaddr + 0x100 - 1, | |
857 | .flags = IORESOURCE_MEM, | |
858 | }, { | |
859 | .start = irq, | |
860 | .flags = IORESOURCE_IRQ, | |
861 | }, { | |
862 | .name = "txx9dmac-chan", | |
863 | .start = dma_base + dma_chan_out, | |
864 | .flags = IORESOURCE_DMA, | |
865 | }, { | |
866 | .name = "txx9dmac-chan", | |
867 | .start = dma_base + dma_chan_in, | |
868 | .flags = IORESOURCE_DMA, | |
869 | } | |
870 | }; | |
871 | struct platform_device *pdev = | |
872 | platform_device_alloc("txx9aclc-ac97", -1); | |
873 | ||
874 | if (!pdev || | |
875 | platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) || | |
876 | platform_device_add(pdev)) | |
877 | platform_device_put(pdev); | |
878 | #endif | |
879 | } | |
c3b28ae2 | 880 | |
269a3eb1 KS |
881 | static struct bus_type txx9_sramc_subsys = { |
882 | .name = "txx9_sram", | |
883 | .dev_name = "txx9_sram", | |
884 | }; | |
c3b28ae2 | 885 | |
269a3eb1 KS |
886 | struct txx9_sramc_dev { |
887 | struct device dev; | |
c3b28ae2 AN |
888 | struct bin_attribute bindata_attr; |
889 | void __iomem *base; | |
890 | }; | |
891 | ||
2c3c8bea | 892 | static ssize_t txx9_sram_read(struct file *filp, struct kobject *kobj, |
c3b28ae2 AN |
893 | struct bin_attribute *bin_attr, |
894 | char *buf, loff_t pos, size_t size) | |
895 | { | |
269a3eb1 | 896 | struct txx9_sramc_dev *dev = bin_attr->private; |
c3b28ae2 AN |
897 | size_t ramsize = bin_attr->size; |
898 | ||
899 | if (pos >= ramsize) | |
900 | return 0; | |
901 | if (pos + size > ramsize) | |
902 | size = ramsize - pos; | |
903 | memcpy_fromio(buf, dev->base + pos, size); | |
904 | return size; | |
905 | } | |
906 | ||
2c3c8bea | 907 | static ssize_t txx9_sram_write(struct file *filp, struct kobject *kobj, |
c3b28ae2 AN |
908 | struct bin_attribute *bin_attr, |
909 | char *buf, loff_t pos, size_t size) | |
910 | { | |
269a3eb1 | 911 | struct txx9_sramc_dev *dev = bin_attr->private; |
c3b28ae2 AN |
912 | size_t ramsize = bin_attr->size; |
913 | ||
914 | if (pos >= ramsize) | |
915 | return 0; | |
916 | if (pos + size > ramsize) | |
917 | size = ramsize - pos; | |
918 | memcpy_toio(dev->base + pos, buf, size); | |
919 | return size; | |
920 | } | |
921 | ||
1610c8a8 LK |
922 | static void txx9_device_release(struct device *dev) |
923 | { | |
924 | struct txx9_sramc_dev *tdev; | |
925 | ||
926 | tdev = container_of(dev, struct txx9_sramc_dev, dev); | |
927 | kfree(tdev); | |
928 | } | |
929 | ||
c3b28ae2 AN |
930 | void __init txx9_sramc_init(struct resource *r) |
931 | { | |
269a3eb1 | 932 | struct txx9_sramc_dev *dev; |
c3b28ae2 AN |
933 | size_t size; |
934 | int err; | |
935 | ||
269a3eb1 KS |
936 | err = subsys_system_register(&txx9_sramc_subsys, NULL); |
937 | if (err) | |
938 | return; | |
c3b28ae2 AN |
939 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
940 | if (!dev) | |
941 | return; | |
942 | size = resource_size(r); | |
943 | dev->base = ioremap(r->start, size); | |
1610c8a8 LK |
944 | if (!dev->base) { |
945 | kfree(dev); | |
946 | return; | |
947 | } | |
948 | dev->dev.release = &txx9_device_release; | |
269a3eb1 | 949 | dev->dev.bus = &txx9_sramc_subsys; |
f937331b | 950 | sysfs_bin_attr_init(&dev->bindata_attr); |
c3b28ae2 AN |
951 | dev->bindata_attr.attr.name = "bindata"; |
952 | dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR; | |
953 | dev->bindata_attr.read = txx9_sram_read; | |
954 | dev->bindata_attr.write = txx9_sram_write; | |
955 | dev->bindata_attr.size = size; | |
956 | dev->bindata_attr.private = dev; | |
269a3eb1 | 957 | err = device_register(&dev->dev); |
c3b28ae2 | 958 | if (err) |
1610c8a8 | 959 | goto exit_put; |
c3b28ae2 AN |
960 | err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr); |
961 | if (err) { | |
269a3eb1 | 962 | device_unregister(&dev->dev); |
1610c8a8 | 963 | iounmap(dev->base); |
c3b28ae2 AN |
964 | kfree(dev); |
965 | } | |
1610c8a8 LK |
966 | return; |
967 | exit_put: | |
968 | put_device(&dev->dev); | |
969 | return; | |
c3b28ae2 | 970 | } |