From: Albert H. <he...@us...> - 2008-03-04 06:20:53
|
Update of /cvsroot/gc-linux/linux/arch/powerpc/platforms/embedded6xx In directory sc8-pr-cvs2.sourceforge.net:/tmp/cvs-serv7117/arch/powerpc/platforms/embedded6xx Added Files: Kconfig Makefile gamecube.c gamecube.h gcn-rsw.c ugecon.c ugecon.h Log Message: Added powerpc arch. Tweaked some driver for wii compatibility. --- NEW FILE: gamecube.h --- /* * arch/powerpc/platforms/embedded6xx/gamecube.h * * Nintendo GameCube board-specific definitions * Copyright (C) 2004-2008 The GameCube Linux Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ #ifndef __MACH_GAMECUBE_H #define __MACH_GAMECUBE_H #define GCN_IO1_PHYS_BASE 0x0c000000 #ifdef CONFIG_GAMECUBE_WII #define GCN_IO2_PHYS_BASE 0x0d000000 #else #define GCN_IO2_PHYS_BASE 0x0c000000 #endif #define GCN_IO1_BASE (0xc0000000 | GCN_IO1_PHYS_BASE) #define GCN_IO2_BASE (0xc0000000 | GCN_IO2_PHYS_BASE) /* * There are 14 IRQs in total. Each has a corresponding bit in both * the Interrupt Cause (ICR) and Interrupt Mask (IMR) registers. * * Enabling/disabling an interrupt line involves asserting/clearing * the corresponding bit in IMR. ACK'ing a request simply involves * asserting the corresponding bit in ICR. */ #define FLIPPER_NR_IRQS (14) #define FLIPPER_ICR ((void __iomem *)(GCN_IO1_BASE+0x3000)) #define FLIPPER_IMR ((void __iomem *)(GCN_IO1_BASE+0x3004)) /* * Anything written here automagically puts us through reset. */ #define FLIPPER_RESET ((void __iomem *)(GCN_IO1_BASE+0x3024)) /* * This is the current memory layout for the GameCube Linux port. * * +------------------------------+ * | framebuffer 640x576x2 bytes | GCN_XFB_END * . . * . . * | framebuffer 640x576x2 bytes | Second buffer * . . * . . * +------------------------------+ GCN_XFB_START * | GX FIFO reserved 256k | GCN_GX_FIFO_END * . . * +------------------------------+ GCN_GX_FIFO_START * | kexec reserved 4x4096 bytes | GCN_KXC_END * . . * +------------------------------+ GCN_KXC_START * | memory remaining bytes | GCN_MEM_END * . . * . . * . . * +- - - - - - - - - - - - - - - + * | Dolphin OS 12544 bytes | * | globals, pre-kernel | * | | * | | * +------------------------------+ GCN_MEM_START * */ /* * XXX * It seems not a good idea to hot change the memory map by simply * changing a video register. * Be conservative here, and assume we're using (or will use) the bigger * of the two framebuffer sizes supported. */ //#define GCN_VIDEO_REG (*((volatile u16*)0xCC002002)) //#define GCN_VIDEO_LINES (((GCN_VIDEO_REG >> 8) & 3) ? 576 : 480) #define GCN_VIDEO_LINES 576 /* * Total amount of RAM found in the system */ #define GCN_RAM_SIZE (24*1024*1024) /* 24 MB */ /* * Size of reserved memory for the video subsystem */ #ifdef CONFIG_FB_GAMECUBE #define GCN_XFB_SIZE (2*640*GCN_VIDEO_LINES*2) /* framebuffer */ #else #define GCN_XFB_SIZE (0) #endif #ifdef CONFIG_FB_GAMECUBE_GX #define GCN_GX_FIFO_SIZE (256*1024) #else #define GCN_GX_FIFO_SIZE (0) #endif /* * Size of reserved memory for kexec compatibility with some homebrew DOLs */ #ifdef CONFIG_KEXEC #define GCN_KXC_SIZE (4*4096) /* PAGE_ALIGN(GCN_PRESERVE_SIZE) */ #else #define GCN_KXC_SIZE (0) #endif /* * Amount of useable memory */ #define GCN_MEM_SIZE (GCN_MEM_END+1) /* * Start and end of several regions */ #define GCN_XFB_END (GCN_RAM_SIZE-1) #define GCN_XFB_START (GCN_XFB_END-GCN_XFB_SIZE+1) #define GCN_GX_FIFO_END (GCN_XFB_START-1) #define GCN_GX_FIFO_START (GCN_GX_FIFO_END-GCN_GX_FIFO_SIZE+1) #define GCN_KXC_END (GCN_GX_FIFO_START-1) #define GCN_KXC_START (GCN_KXC_END-GCN_KXC_SIZE+1) #define GCN_MEM_END (GCN_KXC_START-1) #define GCN_MEM_START (0x00000000) /* * Some memory regions will be preserved across kexec reboots, if enabled. */ #define GCN_PRESERVE_START (0x00000000) #define GCN_PRESERVE_END (0x000030ff) #define GCN_PRESERVE_FROM (GCN_PRESERVE_START) #define GCN_PRESERVE_TO (GCN_KXC_START) #define GCN_PRESERVE_SIZE (GCN_PRESERVE_END+1) /* * These registers control where the visible framebuffer is located. */ #define GCN_VI_TFBL ((void __iomem *)(GCN_IO1_BASE+0x201c)) #define GCN_VI_BFBL ((void __iomem *)(GCN_IO1_BASE+0x2024)) /* arch/ppc/platforms/gcn-time.c */ extern long gcn_time_init(void); extern unsigned long gcn_get_rtc_time(void); extern int gcn_set_rtc_time(unsigned long nowtime); /* arch/ppc/platforms/gcn-con.c */ extern void gcn_con_init(void); #endif /* !__MACH_GAMECUBE_H */ --- NEW FILE: gcn-rsw.c --- /* * arch/powerpc/platforms/embedded6xx/gcn-rsw.c * * Nintendo GameCube reset switch driver * Copyright (C) 2004-2008 The GameCube Linux Team * Copyright (C) 2004 Stefan Esser * Copyright (C) 2004,2005,2008 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/delay.h> #include <linux/reboot.h> #ifdef CONFIG_KEXEC #include <linux/kexec.h> #endif #define RSW_IRQ 1 #define RSW_NORMAL_TIMEOUT 3 /* seconds */ #define RSW_EMERGENCY_PUSHES 10 typedef enum { IDLE = 0, /* nothing to do */ NORMAL_RESET, /* reboot requested */ EMERGENCY_RESET, /* try emergency reboot */ } gcn_rsw_state_t; struct gcn_rsw_private { gcn_rsw_state_t state; struct timer_list timer; unsigned long jiffies; int pushes; int timeout; spinlock_t lock; }; #define DRV_MODULE_NAME "gcn-rsw" #define DRV_DESCRIPTION "Nintendo GameCube reset switch driver" #define DRV_AUTHOR "Stefan Esser <se...@no...>" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE("GPL"); #define PFX DRV_MODULE_NAME ": " #define rsw_printk(level, format, arg...) \ printk(level PFX format , ## arg) /* from kernel/sys.c */ extern void ctrl_alt_del(void); static struct gcn_rsw_private gcn_rsw_private = { .state = IDLE, .timeout = RSW_NORMAL_TIMEOUT, }; /** * */ static void gcn_rsw_normal_reset(unsigned long dummy) { ctrl_alt_del(); } /** * */ static void gcn_rsw_emergency_reset(void) { #ifdef CONFIG_KEXEC struct kimage *image; image = xchg(&kexec_image, 0); if (image) { machine_kexec(image); } #endif machine_restart(NULL); } /** * */ static irqreturn_t gcn_rsw_handler(int this_irq, void *data) { struct gcn_rsw_private *priv = (struct gcn_rsw_private *)data; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); /* someone pushed the reset button */ switch (priv->state) { case IDLE: priv->state = NORMAL_RESET; printk(KERN_EMERG "Rebooting in %d seconds...\n", priv->timeout); printk(KERN_WARNING "Push the Reset button again to cancel reboot!\n"); /* schedule a reboot in a few seconds */ init_timer(&priv->timer); priv->timer.expires = jiffies + priv->timeout * HZ; priv->timer.function = (void (*)(unsigned long))gcn_rsw_normal_reset; add_timer(&priv->timer); priv->jiffies = jiffies; break; case NORMAL_RESET: if (time_before(jiffies, priv->jiffies + priv->timeout * HZ)) { /* the reset button was hit again before deadline */ del_timer(&priv->timer); priv->state = IDLE; printk(KERN_EMERG "Reboot cancelled!\n"); } else { /* * Time expired. System should be now restarting. * Go to emergency mode in case something goes bad. */ priv->state = EMERGENCY_RESET; priv->pushes = 0; printk(KERN_WARNING "SWITCHED TO EMERGENCY RESET MODE!\n" "Push %d times the Reset button to force" " a hard reset!\n" "NOTE THAT THIS COULD CAUSE DATA LOSS!\n", RSW_EMERGENCY_PUSHES); } break; case EMERGENCY_RESET: /* force a hard reset if the user insists ... */ if (++priv->pushes >= RSW_EMERGENCY_PUSHES) { spin_unlock_irqrestore(&priv->lock, flags); gcn_rsw_emergency_reset(); return IRQ_HANDLED; } else { printk(KERN_INFO "%d/%d\n", priv->pushes, RSW_EMERGENCY_PUSHES); } break; } spin_unlock_irqrestore(&priv->lock, flags); return IRQ_HANDLED; } /** * */ static int gcn_rsw_init(void) { int err; spin_lock_init(&gcn_rsw_private.lock); err = request_irq(RSW_IRQ, gcn_rsw_handler, 0, DRV_MODULE_NAME, (void *)&gcn_rsw_private); if (err) { rsw_printk(KERN_ERR, "request of irq%d failed\n", RSW_IRQ); } return err; } /** * */ static void gcn_rsw_exit(void) { free_irq(RSW_IRQ, &gcn_rsw_private); } module_init(gcn_rsw_init); module_exit(gcn_rsw_exit); --- NEW FILE: Kconfig --- config EMBEDDED6xx bool "Embedded 6xx/7xx/7xxx-based boards" depends on PPC32 && BROKEN_ON_SMP && PPC_MULTIPLATFORM config LINKSTATION bool "Linkstation / Kurobox(HG) from Buffalo" depends on EMBEDDED6xx select MPIC select FSL_SOC select PPC_UDBG_16550 if SERIAL_8250 select DEFAULT_UIMAGE help Select LINKSTATION if configuring for one of PPC- (MPC8241) based NAS systems from Buffalo Technology. So far only KuroboxHG has been tested. In the future classical Kurobox, Linkstation-I HD-HLAN and HD-HGLAN versions, and PPC-based Terastation systems should be supported too. config MPC7448HPC2 bool "Freescale MPC7448HPC2(Taiga)" depends on EMBEDDED6xx select TSI108_BRIDGE select DEFAULT_UIMAGE select PPC_UDBG_16550 select WANT_DEVICE_TREE help Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) platform config PPC_HOLLY bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" depends on EMBEDDED6xx select TSI108_BRIDGE select PPC_UDBG_16550 select WANT_DEVICE_TREE help Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval Board with TSI108/9 bridge (Hickory/Holly) config PPC_PRPMC2800 bool "Motorola-PrPMC2800" depends on EMBEDDED6xx select MV64X60 select NOT_COHERENT_CACHE select WANT_DEVICE_TREE help This option enables support for the Motorola PrPMC2800 board config GAMECUBE bool "Nintendo-GameCube" depends on EMBEDDED6xx select NOT_COHERENT_CACHE select WANT_DEVICE_TREE help Select GAMECUBE if configuring for the Nintendo GameCube. More information at: <http://gc-linux.sourceforge.net/> config GAMECUBE_WII bool "Nintendo-Wii" depends on GAMECUBE help Select GAMECUBE_WII if configuring for the Nintendo Wii. More information at: <http://gc-linux.sourceforge.net/> config TSI108_BRIDGE config TSI108_BRIDGE bool depends on MPC7448HPC2 || PPC_HOLLY select PCI select MPIC select MPIC_WEIRD default y config MPC10X_BRIDGE bool depends on LINKSTATION select PPC_INDIRECT_PCI default y config MV64X60 bool select PPC_INDIRECT_PCI select CHECK_CACHE_COHERENCY config MPC10X_OPENPIC bool depends on LINKSTATION default y config MPC10X_STORE_GATHERING bool "Enable MPC10x store gathering" depends on MPC10X_BRIDGE config GAMECUBE_RESET bool "Nintendo GameCube reset button" depends on GAMECUBE default y help If you say yes to this option, support will be included for the reset button of the Nintendo GameCube. If in doubt, say Y here. config USBGECKO_EARLY_CONSOLE bool "Enable USB Gecko early console" depends on GAMECUBE default n help If you say yes to this option, support will be included for the USB Gecko adapter as an early console. If in doubt, say N here. --- NEW FILE: gamecube.c --- /* * arch/powerpc/platforms/embedded6xx/gamecube.c * * Nintendo GameCube board-specific support * Copyright (C) 2004-2008 The GameCube Linux Team * Copyright (C) 2007,2008 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/initrd.h> #include <linux/seq_file.h> #include <linux/kexec.h> #include <asm/io.h> #include <asm/time.h> #include <asm/bitops.h> #include <asm/machdep.h> #include <asm/pgtable.h> #include <asm/prom.h> #include <asm/lmb.h> #include "gamecube.h" #include "ugecon.h" /* * These are used in setup_arch. * */ #define CSR_REG ((void __iomem *)(GCN_IO1_BASE+0x500A)) #define DSP_CSR_PIINT (1<<1) #define DSP_CSR_AIDINT (1<<3) #define DSP_CSR_ARINT (1<<5) #define DSP_CSR_DSPINT (1<<7) #define AUDIO_DMA_LENGTH ((void __iomem *)(GCN_IO1_BASE+0x5036)) #define AI_DCL_PLAY (1<<15) static void __init gamecube_progress(char *s, unsigned short hex) { #ifdef CONFIG_USBGECKO_EARLY_CONSOLE if (s) ug_early_puts(s); ug_early_puts("\n"); #endif } /* * FIXME * We have to get rid of these mappings and move to ioremap. */ extern int map_page(unsigned long va, phys_addr_t pa, int flags); static void dirty_io_block_mapping(unsigned long va, phys_addr_t pa, unsigned int size, int flags) { int i; for (i = 0; i < size; i += PAGE_SIZE) map_page(va + i, pa + i, flags); } static void gamecube_setup_io_mappings(void) { #ifdef CONFIG_GAMECUBE_DEBUG_CONSOLE /* mapping for the debug console framebuffer */ dirty_io_block_mapping(0xd0000000, 0, 0x02000000, _PAGE_IO); #endif /* access to hardware registers */ #ifdef CONFIG_GAMECUBE_WII dirty_io_block_mapping(0xcd000000, 0x0d000000, 0x00010000, _PAGE_IO); #endif dirty_io_block_mapping(0xcc000000, 0x0c000000, 0x00010000, _PAGE_IO); } static void gamecube_restart(char *cmd) { local_irq_disable(); out_8(FLIPPER_RESET, 0x00); } static void gamecube_power_off(void) { local_irq_disable(); for (;;); /* spin until power button pressed */ } static void gamecube_halt(void) { gamecube_restart(NULL); } static unsigned int gamecube_get_irq(void) { int irq; u32 irq_status; irq_status = in_be32(FLIPPER_ICR) & in_be32(FLIPPER_IMR); if (irq_status == 0) return -1; /* no more IRQs pending */ __asm __volatile ("cntlzw %0,%1": "=r"(irq) : "r"(irq_status)); return (31 - irq); } static void flipper_mask_and_ack_irq(unsigned int irq) { clear_bit(irq, FLIPPER_IMR); set_bit(irq, FLIPPER_ICR); } static void flipper_mask_irq(unsigned int irq) { clear_bit(irq, FLIPPER_IMR); } static void flipper_unmask_irq(unsigned int irq) { set_bit(irq, FLIPPER_IMR); } static void flipper_end_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && irq_desc[irq].action) flipper_unmask_irq(irq); } static struct hw_interrupt_type flipper_pic = { .typename = "flipper-pic", .enable = flipper_unmask_irq, .disable = flipper_mask_irq, .ack = flipper_mask_and_ack_irq, .end = flipper_end_irq, }; static void gamecube_init_irq(void) { int i; /* mask and ack all IRQs */ out_be32(FLIPPER_IMR, 0x00000000); out_be32(FLIPPER_ICR, 0xffffffff); for (i = 0; i < FLIPPER_NR_IRQS; i++) irq_desc[i].chip = &flipper_pic; ppc_md.get_irq = gamecube_get_irq; } static void gamecube_show_cpuinfo(struct seq_file *m) { seq_printf(m, "vendor\t\t: IBM\n"); seq_printf(m, "machine\t\t: Nintendo GameCube\n"); } static void gamecube_setup_arch(void) { #ifdef CONFIG_GAMECUBE_DEBUG_CONSOLE gcn_con_init(); #endif #ifdef CONFIG_USBGECKO_EARLY_CONSOLE ug_early_con_init(); #endif #if 0 /* ack and clear the interrupts for the AI line */ out_be16(CSR_REG, DSP_CSR_PIINT|DSP_CSR_AIDINT|DSP_CSR_ARINT|DSP_CSR_DSPINT); /* stop any audio */ out_be16(AUDIO_DMA_LENGTH, in_be16(AUDIO_DMA_LENGTH) & ~AI_DCL_PLAY); #endif } static int __init gamecube_probe(void) { unsigned long dt_root; dt_root = of_get_flat_dt_root(); if (!of_flat_dt_is_compatible(dt_root, "nintendo,gamecube")) return 0; return 1; } #ifdef CONFIG_KEXEC static void gamecube_shutdown(void) { /* currently not used */ } static int gamecube_kexec_prepare(struct kimage *image) { return 0; } #endif /* CONFIG_KEXEC */ define_machine(gamecube) { .name = "gamecube", .probe = gamecube_probe, .setup_arch = gamecube_setup_arch, .setup_io_mappings = gamecube_setup_io_mappings, .show_cpuinfo = gamecube_show_cpuinfo, .init_IRQ = gamecube_init_irq, .calibrate_decr = generic_calibrate_decr, .restart = gamecube_restart, .power_off = gamecube_power_off, .halt = gamecube_halt, .progress = gamecube_progress, #ifdef CONFIG_KEXEC .machine_shutdown = gamecube_shutdown, .machine_kexec_prepare = gamecube_kexec_prepare, .machine_kexec = default_machine_kexec, #endif }; --- NEW FILE: Makefile --- # # Makefile for the 6xx/7xx/7xxxx linux kernel. # obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o obj-$(CONFIG_PPC_HOLLY) += holly.o obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o obj-$(CONFIG_GAMECUBE) += gamecube.o obj-$(CONFIG_GAMECUBE_RESET) += gcn-rsw.o obj-$(CONFIG_USBGECKO_EARLY_CONSOLE) += ugecon.o --- NEW FILE: ugecon.h --- /* * arch/powerpc/platforms/embedded6xx/ugecon.h * * USB Gecko early console on memcard slot B. * Copyright (C) 2008 The GameCube Linux Team * Copyright (C) 2008 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ #ifndef __UGECON_H #define __UGECON_H #ifdef CONFIG_USBGECKO_EARLY_CONSOLE extern void ug_early_putc(char ch); extern void ug_early_puts(char *s); extern void ug_early_con_init(void); #endif /* CONFIG_USBGECKO_EARLY_CONSOLE */ #endif /* __UGECON_H */ --- NEW FILE: ugecon.c --- /* * arch/powerpc/platforms/embedded6xx/ugecon.c * * USB Gecko early console on memcard slot B. * Copyright (C) 2008 The GameCube Linux Team * Copyright (C) 2008 Albert Herranz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * */ #include <linux/kernel.h> #include <linux/io.h> #include <linux/string.h> #include <linux/console.h> #include <asm/processor.h> #include "gamecube.h" #define EXI_BASE (GCN_IO2_BASE+0x6800) #define EXI_CHANNEL_SPACING 0x14 #define EXI_IO_BASE(c) ((void __iomem *)(EXI_BASE + ((c)*EXI_CHANNEL_SPACING))) #define EXI_CLK_32MHZ 5 #define EXI_CSR 0x00 #define EXI_CSR_CLKMASK (0x7<<4) #define EXI_CSR_CLK_32MHZ (EXI_CLK_32MHZ<<4) #define EXI_CSR_CSMASK (0x7<<7) #define EXI_CSR_CS_0 (0x1<<7) /* Chip Select 001 */ #define EXI_CR 0x0c #define EXI_CR_TSTART (1<<0) #define EXI_CR_WRITE (1<<2) #define EXI_CR_READ_WRITE (2<<2) #define EXI_CR_TLEN(len) (((len)-1)<<4) #define EXI_DATA 0x10 /* * */ static int ug_check_adapter(void) { u32 __iomem *csr_reg = EXI_IO_BASE(1) + EXI_CSR; u32 __iomem *data_reg = EXI_IO_BASE(1) + EXI_DATA; u32 __iomem *cr_reg = EXI_IO_BASE(1) + EXI_CR; u32 csr, data, cr; /* select */ csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0; out_be32(csr_reg, csr); /* read/write */ data = 0x90000000; out_be32(data_reg, data); cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART; out_be32(cr_reg, cr); while(in_be32(cr_reg) & EXI_CR_TSTART) barrier(); /* deselect */ out_be32(csr_reg, 0); data = in_be32(data_reg); return (data == 0x04700000); } /* * */ static int ug_is_txfifo_empty(void) { u32 __iomem *csr_reg = EXI_IO_BASE(1) + EXI_CSR; u32 __iomem *data_reg = EXI_IO_BASE(1) + EXI_DATA; u32 __iomem *cr_reg = EXI_IO_BASE(1) + EXI_CR; u32 csr, data, cr; /* select */ csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0; out_be32(csr_reg, csr); /* read/write */ data = 0xC0000000; out_be32(data_reg, data); cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART; out_be32(cr_reg, cr); while(in_be32(cr_reg) & EXI_CR_TSTART) barrier(); /* deselect */ out_be32(csr_reg, 0); data = in_be32(data_reg); return (data & 0x04000000); } /* * */ static void ug_putc(char ch) { u32 __iomem *csr_reg = EXI_IO_BASE(1) + EXI_CSR; u32 __iomem *data_reg = EXI_IO_BASE(1) + EXI_DATA; u32 __iomem *cr_reg = EXI_IO_BASE(1) + EXI_CR; u32 csr, data, cr; /* select */ csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0; out_be32(csr_reg, csr); /* write */ data = 0xb0000000 | (ch << 20); out_be32(data_reg, data); cr = EXI_CR_TLEN(2) | EXI_CR_WRITE | EXI_CR_TSTART; out_be32(cr_reg, cr); while(in_be32(cr_reg) & EXI_CR_TSTART) barrier(); /* deselect */ out_be32(csr_reg, 0); } /* * */ void ug_early_putc(char ch) { int count = 10; while(!ug_is_txfifo_empty() && count--) barrier(); ug_putc(ch); } /* * */ void ug_early_puts(char *s) { while(*s) { if (*s == '\n') ug_early_putc('\r'); ug_early_putc(*s++); } } /* * */ static void ug_early_con_write(struct console *co, const char *buf, unsigned int count) { char *b = (char *)buf; while (count--) { if (*b == '\n') ug_early_putc('\r'); ug_early_putc(*b++); } } static struct console ug_early_con = { .name = "ugecon", .flags = CON_PRINTBUFFER | CON_BOOT, .index = -1, }; /* * */ void ug_early_con_init(void) { if (ug_check_adapter()) { ug_early_puts("ugecon: early console initialized.\n"); ug_early_con.write = ug_early_con_write; register_console(&ug_early_con); } } |