| /* |
| * Alchemy/AMD/RMI DB1200 board setup. |
| * |
| * Licensed under the terms outlined in the file COPYING in the root of |
| * this source archive. |
| */ |
| |
| #include <linux/init.h> |
| #include <linux/interrupt.h> |
| #include <linux/io.h> |
| #include <linux/kernel.h> |
| #include <asm/mach-au1x00/au1000.h> |
| #include <asm/mach-db1x00/bcsr.h> |
| #include <asm/mach-db1x00/db1200.h> |
| |
| const char *get_system_type(void) |
| { |
| return "Alchemy Db1200"; |
| } |
| |
| void __init board_setup(void) |
| { |
| unsigned long freq0, clksrc, div, pfc; |
| unsigned short whoami; |
| |
| bcsr_init(DB1200_BCSR_PHYS_ADDR, |
| DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS); |
| |
| whoami = bcsr_read(BCSR_WHOAMI); |
| printk(KERN_INFO "Alchemy/AMD/RMI DB1200 Board, CPLD Rev %d" |
| " Board-ID %d Daughtercard ID %d\n", |
| (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf); |
| |
| /* SMBus/SPI on PSC0, Audio on PSC1 */ |
| pfc = __raw_readl((void __iomem *)SYS_PINFUNC); |
| pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); |
| pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3); |
| pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */ |
| __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); |
| wmb(); |
| |
| /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from |
| * CPU clock; all other clock generators off/unused. |
| */ |
| div = (get_au1x00_speed() + 25000000) / 50000000; |
| if (div & 1) |
| div++; |
| div = ((div >> 1) - 1) & 0xff; |
| |
| freq0 = div << SYS_FC_FRDIV0_BIT; |
| __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); |
| wmb(); |
| freq0 |= SYS_FC_FE0; /* enable F0 */ |
| __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); |
| wmb(); |
| |
| /* psc0_intclk comes 1:1 from F0 */ |
| clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT; |
| __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC); |
| wmb(); |
| } |
| |
| /* use the hexleds to count the number of times the cpu has entered |
| * wait, the dots to indicate whether the CPU is currently idle or |
| * active (dots off = sleeping, dots on = working) for cases where |
| * the number doesn't change for a long(er) period of time. |
| */ |
| static void db1200_wait(void) |
| { |
| __asm__(" .set push \n" |
| " .set mips3 \n" |
| " .set noreorder \n" |
| " cache 0x14, 0(%0) \n" |
| " cache 0x14, 32(%0) \n" |
| " cache 0x14, 64(%0) \n" |
| /* dots off: we're about to call wait */ |
| " lui $26, 0xb980 \n" |
| " ori $27, $0, 3 \n" |
| " sb $27, 0x18($26) \n" |
| " sync \n" |
| " nop \n" |
| " wait \n" |
| " nop \n" |
| " nop \n" |
| " nop \n" |
| " nop \n" |
| " nop \n" |
| /* dots on: there's work to do, increment cntr */ |
| " lui $26, 0xb980 \n" |
| " sb $0, 0x18($26) \n" |
| " lui $26, 0xb9c0 \n" |
| " lb $27, 0($26) \n" |
| " addiu $27, $27, 1 \n" |
| " sb $27, 0($26) \n" |
| " sync \n" |
| " .set pop \n" |
| : : "r" (db1200_wait)); |
| } |
| |
| static int __init db1200_arch_init(void) |
| { |
| /* GPIO7 is low-level triggered CPLD cascade */ |
| set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW); |
| bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT); |
| |
| /* do not autoenable these: CPLD has broken edge int handling, |
| * and the CD handler setup requires manual enabling to work |
| * around that. |
| */ |
| irq_to_desc(DB1200_SD0_INSERT_INT)->status |= IRQ_NOAUTOEN; |
| irq_to_desc(DB1200_SD0_EJECT_INT)->status |= IRQ_NOAUTOEN; |
| |
| if (cpu_wait) |
| cpu_wait = db1200_wait; |
| |
| return 0; |
| } |
| arch_initcall(db1200_arch_init); |