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