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/txx9/generic.h> 29 #include <asm/txx9/pci.h> 30 #ifdef CONFIG_CPU_TX49XX 31 #include <asm/txx9/tx4938.h> 32 #endif 33 34 /* EBUSC settings of TX4927, etc. */ 35 struct resource txx9_ce_res[8]; 36 static char txx9_ce_res_name[8][4]; /* "CEn" */ 37 38 /* pcode, internal register */ 39 unsigned int txx9_pcode; 40 char txx9_pcode_str[8]; 41 static struct resource txx9_reg_res = { 42 .name = txx9_pcode_str, 43 .flags = IORESOURCE_MEM, 44 }; 45 void __init 46 txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size) 47 { 48 int i; 49 50 for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) { 51 sprintf(txx9_ce_res_name[i], "CE%d", i); 52 txx9_ce_res[i].flags = IORESOURCE_MEM; 53 txx9_ce_res[i].name = txx9_ce_res_name[i]; 54 } 55 56 sprintf(txx9_pcode_str, "TX%x", pcode); 57 if (base) { 58 txx9_reg_res.start = base & 0xfffffffffULL; 59 txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1); 60 request_resource(&iomem_resource, &txx9_reg_res); 61 } 62 } 63 64 /* clocks */ 65 unsigned int txx9_master_clock; 66 unsigned int txx9_cpu_clock; 67 unsigned int txx9_gbus_clock; 68 69 int txx9_ccfg_toeon __initdata = 1; 70 71 /* Minimum CLK support */ 72 73 struct clk *clk_get(struct device *dev, const char *id) 74 { 75 if (!strcmp(id, "spi-baseclk")) 76 return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 4); 77 if (!strcmp(id, "imbus_clk")) 78 return (struct clk *)((unsigned long)txx9_gbus_clock / 2); 79 return ERR_PTR(-ENOENT); 80 } 81 EXPORT_SYMBOL(clk_get); 82 83 int clk_enable(struct clk *clk) 84 { 85 return 0; 86 } 87 EXPORT_SYMBOL(clk_enable); 88 89 void clk_disable(struct clk *clk) 90 { 91 } 92 EXPORT_SYMBOL(clk_disable); 93 94 unsigned long clk_get_rate(struct clk *clk) 95 { 96 return (unsigned long)clk; 97 } 98 EXPORT_SYMBOL(clk_get_rate); 99 100 void clk_put(struct clk *clk) 101 { 102 } 103 EXPORT_SYMBOL(clk_put); 104 105 /* GPIO support */ 106 107 #ifdef CONFIG_GENERIC_GPIO 108 int gpio_to_irq(unsigned gpio) 109 { 110 return -EINVAL; 111 } 112 EXPORT_SYMBOL(gpio_to_irq); 113 114 int irq_to_gpio(unsigned irq) 115 { 116 return -EINVAL; 117 } 118 EXPORT_SYMBOL(irq_to_gpio); 119 #endif 120 121 extern struct txx9_board_vec jmr3927_vec; 122 extern struct txx9_board_vec rbtx4927_vec; 123 extern struct txx9_board_vec rbtx4937_vec; 124 extern struct txx9_board_vec rbtx4938_vec; 125 126 struct txx9_board_vec *txx9_board_vec __initdata; 127 static char txx9_system_type[32]; 128 129 void __init prom_init_cmdline(void) 130 { 131 int argc = (int)fw_arg0; 132 char **argv = (char **)fw_arg1; 133 int i; /* Always ignore the "-c" at argv[0] */ 134 #ifdef CONFIG_64BIT 135 char *fixed_argv[32]; 136 for (i = 0; i < argc; i++) 137 fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i)); 138 argv = fixed_argv; 139 #endif 140 141 /* ignore all built-in args if any f/w args given */ 142 if (argc > 1) 143 *arcs_cmdline = '\0'; 144 145 for (i = 1; i < argc; i++) { 146 if (i != 1) 147 strcat(arcs_cmdline, " "); 148 strcat(arcs_cmdline, argv[i]); 149 } 150 } 151 152 void __init prom_init(void) 153 { 154 #ifdef CONFIG_CPU_TX39XX 155 txx9_board_vec = &jmr3927_vec; 156 #endif 157 #ifdef CONFIG_CPU_TX49XX 158 switch (TX4938_REV_PCODE()) { 159 #ifdef CONFIG_TOSHIBA_RBTX4927 160 case 0x4927: 161 txx9_board_vec = &rbtx4927_vec; 162 break; 163 case 0x4937: 164 txx9_board_vec = &rbtx4937_vec; 165 break; 166 #endif 167 #ifdef CONFIG_TOSHIBA_RBTX4938 168 case 0x4938: 169 txx9_board_vec = &rbtx4938_vec; 170 break; 171 #endif 172 } 173 #endif 174 175 strcpy(txx9_system_type, txx9_board_vec->system); 176 177 txx9_board_vec->prom_init(); 178 } 179 180 void __init prom_free_prom_memory(void) 181 { 182 } 183 184 const char *get_system_type(void) 185 { 186 return txx9_system_type; 187 } 188 189 char * __init prom_getcmdline(void) 190 { 191 return &(arcs_cmdline[0]); 192 } 193 194 static void __noreturn txx9_machine_halt(void) 195 { 196 local_irq_disable(); 197 clear_c0_status(ST0_IM); 198 while (1) { 199 if (cpu_wait) { 200 (*cpu_wait)(); 201 if (cpu_has_counter) { 202 /* 203 * Clear counter interrupt while it 204 * breaks WAIT instruction even if 205 * masked. 206 */ 207 write_c0_compare(0); 208 } 209 } 210 } 211 } 212 213 /* Watchdog support */ 214 void __init txx9_wdt_init(unsigned long base) 215 { 216 struct resource res = { 217 .start = base, 218 .end = base + 0x100 - 1, 219 .flags = IORESOURCE_MEM, 220 }; 221 platform_device_register_simple("txx9wdt", -1, &res, 1); 222 } 223 224 /* SPI support */ 225 void __init txx9_spi_init(int busid, unsigned long base, int irq) 226 { 227 struct resource res[] = { 228 { 229 .start = base, 230 .end = base + 0x20 - 1, 231 .flags = IORESOURCE_MEM, 232 }, { 233 .start = irq, 234 .flags = IORESOURCE_IRQ, 235 }, 236 }; 237 platform_device_register_simple("spi_txx9", busid, 238 res, ARRAY_SIZE(res)); 239 } 240 241 void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr) 242 { 243 struct platform_device *pdev = 244 platform_device_alloc("tc35815-mac", id); 245 if (!pdev || 246 platform_device_add_data(pdev, ethaddr, 6) || 247 platform_device_add(pdev)) 248 platform_device_put(pdev); 249 } 250 251 void __init txx9_sio_init(unsigned long baseaddr, int irq, 252 unsigned int line, unsigned int sclk, int nocts) 253 { 254 #ifdef CONFIG_SERIAL_TXX9 255 struct uart_port req; 256 257 memset(&req, 0, sizeof(req)); 258 req.line = line; 259 req.iotype = UPIO_MEM; 260 req.membase = ioremap(baseaddr, 0x24); 261 req.mapbase = baseaddr; 262 req.irq = irq; 263 if (!nocts) 264 req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; 265 if (sclk) { 266 req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/; 267 req.uartclk = sclk; 268 } else 269 req.uartclk = TXX9_IMCLK; 270 early_serial_txx9_setup(&req); 271 #endif /* CONFIG_SERIAL_TXX9 */ 272 } 273 274 #ifdef CONFIG_EARLY_PRINTK 275 static void __init null_prom_putchar(char c) 276 { 277 } 278 void (*txx9_prom_putchar)(char c) __initdata = null_prom_putchar; 279 280 void __init prom_putchar(char c) 281 { 282 txx9_prom_putchar(c); 283 } 284 285 static void __iomem *early_txx9_sio_port; 286 287 static void __init early_txx9_sio_putchar(char c) 288 { 289 #define TXX9_SICISR 0x0c 290 #define TXX9_SITFIFO 0x1c 291 #define TXX9_SICISR_TXALS 0x00000002 292 while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) & 293 TXX9_SICISR_TXALS)) 294 ; 295 __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO); 296 } 297 298 void __init txx9_sio_putchar_init(unsigned long baseaddr) 299 { 300 early_txx9_sio_port = ioremap(baseaddr, 0x24); 301 txx9_prom_putchar = early_txx9_sio_putchar; 302 } 303 #endif /* CONFIG_EARLY_PRINTK */ 304 305 /* wrappers */ 306 void __init plat_mem_setup(void) 307 { 308 ioport_resource.start = 0; 309 ioport_resource.end = ~0UL; /* no limit */ 310 iomem_resource.start = 0; 311 iomem_resource.end = ~0UL; /* no limit */ 312 313 /* fallback restart/halt routines */ 314 _machine_restart = (void (*)(char *))txx9_machine_halt; 315 _machine_halt = txx9_machine_halt; 316 pm_power_off = txx9_machine_halt; 317 318 #ifdef CONFIG_PCI 319 pcibios_plat_setup = txx9_pcibios_setup; 320 #endif 321 txx9_board_vec->mem_setup(); 322 } 323 324 void __init arch_init_irq(void) 325 { 326 txx9_board_vec->irq_setup(); 327 } 328 329 void __init plat_time_init(void) 330 { 331 txx9_board_vec->time_init(); 332 } 333 334 static int __init _txx9_arch_init(void) 335 { 336 if (txx9_board_vec->arch_init) 337 txx9_board_vec->arch_init(); 338 return 0; 339 } 340 arch_initcall(_txx9_arch_init); 341 342 static int __init _txx9_device_init(void) 343 { 344 if (txx9_board_vec->device_init) 345 txx9_board_vec->device_init(); 346 return 0; 347 } 348 device_initcall(_txx9_device_init); 349 350 int (*txx9_irq_dispatch)(int pending); 351 asmlinkage void plat_irq_dispatch(void) 352 { 353 int pending = read_c0_status() & read_c0_cause() & ST0_IM; 354 int irq = txx9_irq_dispatch(pending); 355 356 if (likely(irq >= 0)) 357 do_IRQ(irq); 358 else 359 spurious_interrupt(); 360 } 361 362 /* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */ 363 #ifdef NEEDS_TXX9_SWIZZLE_ADDR_B 364 static unsigned long __swizzle_addr_none(unsigned long port) 365 { 366 return port; 367 } 368 unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none; 369 EXPORT_SYMBOL(__swizzle_addr_b); 370 #endif 371