1 /* 2 * linux/arch/mips/txx9/generic/setup.c 3 * 4 * Based on linux/arch/mips/txx9/rbtx4938/setup.c, 5 * and RBTX49xx patch from CELF patch archive. 6 * 7 * 2003-2005 (c) MontaVista Software, Inc. 8 * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file "COPYING" in the main directory of this archive 12 * for more details. 13 */ 14 #include <linux/init.h> 15 #include <linux/kernel.h> 16 #include <linux/types.h> 17 #include <linux/interrupt.h> 18 #include <linux/string.h> 19 #include <linux/module.h> 20 #include <linux/clk.h> 21 #include <linux/err.h> 22 #include <linux/gpio.h> 23 #include <linux/platform_device.h> 24 #include <linux/serial_core.h> 25 #include <asm/bootinfo.h> 26 #include <asm/time.h> 27 #include <asm/reboot.h> 28 #include <asm/r4kcache.h> 29 #include <asm/txx9/generic.h> 30 #include <asm/txx9/pci.h> 31 #ifdef CONFIG_CPU_TX49XX 32 #include <asm/txx9/tx4938.h> 33 #endif 34 35 /* EBUSC settings of TX4927, etc. */ 36 struct resource txx9_ce_res[8]; 37 static char txx9_ce_res_name[8][4]; /* "CEn" */ 38 39 /* pcode, internal register */ 40 unsigned int txx9_pcode; 41 char txx9_pcode_str[8]; 42 static struct resource txx9_reg_res = { 43 .name = txx9_pcode_str, 44 .flags = IORESOURCE_MEM, 45 }; 46 void __init 47 txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size) 48 { 49 int i; 50 51 for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) { 52 sprintf(txx9_ce_res_name[i], "CE%d", i); 53 txx9_ce_res[i].flags = IORESOURCE_MEM; 54 txx9_ce_res[i].name = txx9_ce_res_name[i]; 55 } 56 57 txx9_pcode = pcode; 58 sprintf(txx9_pcode_str, "TX%x", pcode); 59 if (base) { 60 txx9_reg_res.start = base & 0xfffffffffULL; 61 txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1); 62 request_resource(&iomem_resource, &txx9_reg_res); 63 } 64 } 65 66 /* clocks */ 67 unsigned int txx9_master_clock; 68 unsigned int txx9_cpu_clock; 69 unsigned int txx9_gbus_clock; 70 71 #ifdef CONFIG_CPU_TX39XX 72 /* don't enable by default - see errata */ 73 int txx9_ccfg_toeon __initdata; 74 #else 75 int txx9_ccfg_toeon __initdata = 1; 76 #endif 77 78 /* Minimum CLK support */ 79 80 struct clk *clk_get(struct device *dev, const char *id) 81 { 82 if (!strcmp(id, "spi-baseclk")) 83 return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 4); 84 if (!strcmp(id, "imbus_clk")) 85 return (struct clk *)((unsigned long)txx9_gbus_clock / 2); 86 return ERR_PTR(-ENOENT); 87 } 88 EXPORT_SYMBOL(clk_get); 89 90 int clk_enable(struct clk *clk) 91 { 92 return 0; 93 } 94 EXPORT_SYMBOL(clk_enable); 95 96 void clk_disable(struct clk *clk) 97 { 98 } 99 EXPORT_SYMBOL(clk_disable); 100 101 unsigned long clk_get_rate(struct clk *clk) 102 { 103 return (unsigned long)clk; 104 } 105 EXPORT_SYMBOL(clk_get_rate); 106 107 void clk_put(struct clk *clk) 108 { 109 } 110 EXPORT_SYMBOL(clk_put); 111 112 /* GPIO support */ 113 114 #ifdef CONFIG_GENERIC_GPIO 115 int gpio_to_irq(unsigned gpio) 116 { 117 return -EINVAL; 118 } 119 EXPORT_SYMBOL(gpio_to_irq); 120 121 int irq_to_gpio(unsigned irq) 122 { 123 return -EINVAL; 124 } 125 EXPORT_SYMBOL(irq_to_gpio); 126 #endif 127 128 #define BOARD_VEC(board) extern struct txx9_board_vec board; 129 #include <asm/txx9/boards.h> 130 #undef BOARD_VEC 131 132 struct txx9_board_vec *txx9_board_vec __initdata; 133 static char txx9_system_type[32]; 134 135 static struct txx9_board_vec *board_vecs[] __initdata = { 136 #define BOARD_VEC(board) &board, 137 #include <asm/txx9/boards.h> 138 #undef BOARD_VEC 139 }; 140 141 static struct txx9_board_vec *__init find_board_byname(const char *name) 142 { 143 int i; 144 145 /* search board_vecs table */ 146 for (i = 0; i < ARRAY_SIZE(board_vecs); i++) { 147 if (strstr(board_vecs[i]->system, name)) 148 return board_vecs[i]; 149 } 150 return NULL; 151 } 152 153 static void __init prom_init_cmdline(void) 154 { 155 int argc = (int)fw_arg0; 156 int *argv32 = (int *)fw_arg1; 157 int i; /* Always ignore the "-c" at argv[0] */ 158 char builtin[CL_SIZE]; 159 160 /* ignore all built-in args if any f/w args given */ 161 /* 162 * But if built-in strings was started with '+', append them 163 * to command line args. If built-in was started with '-', 164 * ignore all f/w args. 165 */ 166 builtin[0] = '\0'; 167 if (arcs_cmdline[0] == '+') 168 strcpy(builtin, arcs_cmdline + 1); 169 else if (arcs_cmdline[0] == '-') { 170 strcpy(builtin, arcs_cmdline + 1); 171 argc = 0; 172 } else if (argc <= 1) 173 strcpy(builtin, arcs_cmdline); 174 arcs_cmdline[0] = '\0'; 175 176 for (i = 1; i < argc; i++) { 177 char *str = (char *)(long)argv32[i]; 178 if (i != 1) 179 strcat(arcs_cmdline, " "); 180 if (strchr(str, ' ')) { 181 strcat(arcs_cmdline, "\""); 182 strcat(arcs_cmdline, str); 183 strcat(arcs_cmdline, "\""); 184 } else 185 strcat(arcs_cmdline, str); 186 } 187 /* append saved builtin args */ 188 if (builtin[0]) { 189 if (arcs_cmdline[0]) 190 strcat(arcs_cmdline, " "); 191 strcat(arcs_cmdline, builtin); 192 } 193 } 194 195 static int txx9_ic_disable __initdata; 196 static int txx9_dc_disable __initdata; 197 198 #if defined(CONFIG_CPU_TX49XX) 199 /* flush all cache on very early stage (before 4k_cache_init) */ 200 static void __init early_flush_dcache(void) 201 { 202 unsigned int conf = read_c0_config(); 203 unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6)); 204 unsigned int linesz = 32; 205 unsigned long addr, end; 206 207 end = INDEX_BASE + dc_size / 4; 208 /* 4way, waybit=0 */ 209 for (addr = INDEX_BASE; addr < end; addr += linesz) { 210 cache_op(Index_Writeback_Inv_D, addr | 0); 211 cache_op(Index_Writeback_Inv_D, addr | 1); 212 cache_op(Index_Writeback_Inv_D, addr | 2); 213 cache_op(Index_Writeback_Inv_D, addr | 3); 214 } 215 } 216 217 static void __init txx9_cache_fixup(void) 218 { 219 unsigned int conf; 220 221 conf = read_c0_config(); 222 /* flush and disable */ 223 if (txx9_ic_disable) { 224 conf |= TX49_CONF_IC; 225 write_c0_config(conf); 226 } 227 if (txx9_dc_disable) { 228 early_flush_dcache(); 229 conf |= TX49_CONF_DC; 230 write_c0_config(conf); 231 } 232 233 /* enable cache */ 234 conf = read_c0_config(); 235 if (!txx9_ic_disable) 236 conf &= ~TX49_CONF_IC; 237 if (!txx9_dc_disable) 238 conf &= ~TX49_CONF_DC; 239 write_c0_config(conf); 240 241 if (conf & TX49_CONF_IC) 242 pr_info("TX49XX I-Cache disabled.\n"); 243 if (conf & TX49_CONF_DC) 244 pr_info("TX49XX D-Cache disabled.\n"); 245 } 246 #elif defined(CONFIG_CPU_TX39XX) 247 /* flush all cache on very early stage (before tx39_cache_init) */ 248 static void __init early_flush_dcache(void) 249 { 250 unsigned int conf = read_c0_config(); 251 unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >> 252 TX39_CONF_DCS_SHIFT)); 253 unsigned int linesz = 16; 254 unsigned long addr, end; 255 256 end = INDEX_BASE + dc_size / 2; 257 /* 2way, waybit=0 */ 258 for (addr = INDEX_BASE; addr < end; addr += linesz) { 259 cache_op(Index_Writeback_Inv_D, addr | 0); 260 cache_op(Index_Writeback_Inv_D, addr | 1); 261 } 262 } 263 264 static void __init txx9_cache_fixup(void) 265 { 266 unsigned int conf; 267 268 conf = read_c0_config(); 269 /* flush and disable */ 270 if (txx9_ic_disable) { 271 conf &= ~TX39_CONF_ICE; 272 write_c0_config(conf); 273 } 274 if (txx9_dc_disable) { 275 early_flush_dcache(); 276 conf &= ~TX39_CONF_DCE; 277 write_c0_config(conf); 278 } 279 280 /* enable cache */ 281 conf = read_c0_config(); 282 if (!txx9_ic_disable) 283 conf |= TX39_CONF_ICE; 284 if (!txx9_dc_disable) 285 conf |= TX39_CONF_DCE; 286 write_c0_config(conf); 287 288 if (!(conf & TX39_CONF_ICE)) 289 pr_info("TX39XX I-Cache disabled.\n"); 290 if (!(conf & TX39_CONF_DCE)) 291 pr_info("TX39XX D-Cache disabled.\n"); 292 } 293 #else 294 static inline void txx9_cache_fixup(void) 295 { 296 } 297 #endif 298 299 static void __init preprocess_cmdline(void) 300 { 301 char cmdline[CL_SIZE]; 302 char *s; 303 304 strcpy(cmdline, arcs_cmdline); 305 s = cmdline; 306 arcs_cmdline[0] = '\0'; 307 while (s && *s) { 308 char *str = strsep(&s, " "); 309 if (strncmp(str, "board=", 6) == 0) { 310 txx9_board_vec = find_board_byname(str + 6); 311 continue; 312 } else if (strncmp(str, "masterclk=", 10) == 0) { 313 unsigned long val; 314 if (strict_strtoul(str + 10, 10, &val) == 0) 315 txx9_master_clock = val; 316 continue; 317 } else if (strcmp(str, "icdisable") == 0) { 318 txx9_ic_disable = 1; 319 continue; 320 } else if (strcmp(str, "dcdisable") == 0) { 321 txx9_dc_disable = 1; 322 continue; 323 } else if (strcmp(str, "toeoff") == 0) { 324 txx9_ccfg_toeon = 0; 325 continue; 326 } else if (strcmp(str, "toeon") == 0) { 327 txx9_ccfg_toeon = 1; 328 continue; 329 } 330 if (arcs_cmdline[0]) 331 strcat(arcs_cmdline, " "); 332 strcat(arcs_cmdline, str); 333 } 334 335 txx9_cache_fixup(); 336 } 337 338 static void __init select_board(void) 339 { 340 const char *envstr; 341 342 /* first, determine by "board=" argument in preprocess_cmdline() */ 343 if (txx9_board_vec) 344 return; 345 /* next, determine by "board" envvar */ 346 envstr = prom_getenv("board"); 347 if (envstr) { 348 txx9_board_vec = find_board_byname(envstr); 349 if (txx9_board_vec) 350 return; 351 } 352 353 /* select "default" board */ 354 #ifdef CONFIG_CPU_TX39XX 355 txx9_board_vec = &jmr3927_vec; 356 #endif 357 #ifdef CONFIG_CPU_TX49XX 358 switch (TX4938_REV_PCODE()) { 359 #ifdef CONFIG_TOSHIBA_RBTX4927 360 case 0x4927: 361 txx9_board_vec = &rbtx4927_vec; 362 break; 363 case 0x4937: 364 txx9_board_vec = &rbtx4937_vec; 365 break; 366 #endif 367 #ifdef CONFIG_TOSHIBA_RBTX4938 368 case 0x4938: 369 txx9_board_vec = &rbtx4938_vec; 370 break; 371 #endif 372 } 373 #endif 374 } 375 376 void __init prom_init(void) 377 { 378 prom_init_cmdline(); 379 preprocess_cmdline(); 380 select_board(); 381 382 strcpy(txx9_system_type, txx9_board_vec->system); 383 384 txx9_board_vec->prom_init(); 385 } 386 387 void __init prom_free_prom_memory(void) 388 { 389 } 390 391 const char *get_system_type(void) 392 { 393 return txx9_system_type; 394 } 395 396 char * __init prom_getcmdline(void) 397 { 398 return &(arcs_cmdline[0]); 399 } 400 401 const char *__init prom_getenv(const char *name) 402 { 403 const s32 *str = (const s32 *)fw_arg2; 404 405 if (!str) 406 return NULL; 407 /* YAMON style ("name", "value" pairs) */ 408 while (str[0] && str[1]) { 409 if (!strcmp((const char *)(unsigned long)str[0], name)) 410 return (const char *)(unsigned long)str[1]; 411 str += 2; 412 } 413 return NULL; 414 } 415 416 static void __noreturn txx9_machine_halt(void) 417 { 418 local_irq_disable(); 419 clear_c0_status(ST0_IM); 420 while (1) { 421 if (cpu_wait) { 422 (*cpu_wait)(); 423 if (cpu_has_counter) { 424 /* 425 * Clear counter interrupt while it 426 * breaks WAIT instruction even if 427 * masked. 428 */ 429 write_c0_compare(0); 430 } 431 } 432 } 433 } 434 435 /* Watchdog support */ 436 void __init txx9_wdt_init(unsigned long base) 437 { 438 struct resource res = { 439 .start = base, 440 .end = base + 0x100 - 1, 441 .flags = IORESOURCE_MEM, 442 }; 443 platform_device_register_simple("txx9wdt", -1, &res, 1); 444 } 445 446 /* SPI support */ 447 void __init txx9_spi_init(int busid, unsigned long base, int irq) 448 { 449 struct resource res[] = { 450 { 451 .start = base, 452 .end = base + 0x20 - 1, 453 .flags = IORESOURCE_MEM, 454 }, { 455 .start = irq, 456 .flags = IORESOURCE_IRQ, 457 }, 458 }; 459 platform_device_register_simple("spi_txx9", busid, 460 res, ARRAY_SIZE(res)); 461 } 462 463 void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr) 464 { 465 struct platform_device *pdev = 466 platform_device_alloc("tc35815-mac", id); 467 if (!pdev || 468 platform_device_add_data(pdev, ethaddr, 6) || 469 platform_device_add(pdev)) 470 platform_device_put(pdev); 471 } 472 473 void __init txx9_sio_init(unsigned long baseaddr, int irq, 474 unsigned int line, unsigned int sclk, int nocts) 475 { 476 #ifdef CONFIG_SERIAL_TXX9 477 struct uart_port req; 478 479 memset(&req, 0, sizeof(req)); 480 req.line = line; 481 req.iotype = UPIO_MEM; 482 req.membase = ioremap(baseaddr, 0x24); 483 req.mapbase = baseaddr; 484 req.irq = irq; 485 if (!nocts) 486 req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; 487 if (sclk) { 488 req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/; 489 req.uartclk = sclk; 490 } else 491 req.uartclk = TXX9_IMCLK; 492 early_serial_txx9_setup(&req); 493 #endif /* CONFIG_SERIAL_TXX9 */ 494 } 495 496 #ifdef CONFIG_EARLY_PRINTK 497 static void __init null_prom_putchar(char c) 498 { 499 } 500 void (*txx9_prom_putchar)(char c) __initdata = null_prom_putchar; 501 502 void __init prom_putchar(char c) 503 { 504 txx9_prom_putchar(c); 505 } 506 507 static void __iomem *early_txx9_sio_port; 508 509 static void __init early_txx9_sio_putchar(char c) 510 { 511 #define TXX9_SICISR 0x0c 512 #define TXX9_SITFIFO 0x1c 513 #define TXX9_SICISR_TXALS 0x00000002 514 while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) & 515 TXX9_SICISR_TXALS)) 516 ; 517 __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO); 518 } 519 520 void __init txx9_sio_putchar_init(unsigned long baseaddr) 521 { 522 early_txx9_sio_port = ioremap(baseaddr, 0x24); 523 txx9_prom_putchar = early_txx9_sio_putchar; 524 } 525 #endif /* CONFIG_EARLY_PRINTK */ 526 527 /* wrappers */ 528 void __init plat_mem_setup(void) 529 { 530 ioport_resource.start = 0; 531 ioport_resource.end = ~0UL; /* no limit */ 532 iomem_resource.start = 0; 533 iomem_resource.end = ~0UL; /* no limit */ 534 535 /* fallback restart/halt routines */ 536 _machine_restart = (void (*)(char *))txx9_machine_halt; 537 _machine_halt = txx9_machine_halt; 538 pm_power_off = txx9_machine_halt; 539 540 #ifdef CONFIG_PCI 541 pcibios_plat_setup = txx9_pcibios_setup; 542 #endif 543 txx9_board_vec->mem_setup(); 544 } 545 546 void __init arch_init_irq(void) 547 { 548 txx9_board_vec->irq_setup(); 549 } 550 551 void __init plat_time_init(void) 552 { 553 #ifdef CONFIG_CPU_TX49XX 554 mips_hpt_frequency = txx9_cpu_clock / 2; 555 #endif 556 txx9_board_vec->time_init(); 557 } 558 559 static int __init _txx9_arch_init(void) 560 { 561 if (txx9_board_vec->arch_init) 562 txx9_board_vec->arch_init(); 563 return 0; 564 } 565 arch_initcall(_txx9_arch_init); 566 567 static int __init _txx9_device_init(void) 568 { 569 if (txx9_board_vec->device_init) 570 txx9_board_vec->device_init(); 571 return 0; 572 } 573 device_initcall(_txx9_device_init); 574 575 int (*txx9_irq_dispatch)(int pending); 576 asmlinkage void plat_irq_dispatch(void) 577 { 578 int pending = read_c0_status() & read_c0_cause() & ST0_IM; 579 int irq = txx9_irq_dispatch(pending); 580 581 if (likely(irq >= 0)) 582 do_IRQ(irq); 583 else 584 spurious_interrupt(); 585 } 586 587 /* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */ 588 #ifdef NEEDS_TXX9_SWIZZLE_ADDR_B 589 static unsigned long __swizzle_addr_none(unsigned long port) 590 { 591 return port; 592 } 593 unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none; 594 EXPORT_SYMBOL(__swizzle_addr_b); 595 #endif 596