From 0905780aae58ea69f2dafea9716ee2ea78dbe4e2 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 13 Jun 2005 19:58:50 +0000 Subject: [MIPS] zs.c: Resurrect the deceased zs.c for now. Not that it's meant to be sustained for long, but from time to time it's useful to have some console... Signed-off-by: Maciej W. Rozycki Signed-off-by: Ralf Baechle --- drivers/tc/zs.c | 150 ++++++++++++++++++++++++-------------------------------- drivers/tc/zs.h | 13 +++-- 2 files changed, 70 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index c52af73a251..6756d0fab6f 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -6,7 +6,7 @@ * * DECstation changes * Copyright (C) 1998-2000 Harald Koerfgen - * Copyright (C) 2000, 2001, 2002, 2003, 2004 Maciej W. Rozycki + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Maciej W. Rozycki * * For the rest of the code the original Copyright applies: * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) @@ -55,6 +55,7 @@ #include #include #include +#include #ifdef CONFIG_SERIAL_DEC_CONSOLE #include #endif @@ -63,7 +64,6 @@ #include #include #include -#include #include #include @@ -128,6 +128,8 @@ static struct zs_parms ds_parms = { #define BUS_PRESENT (DS_BUS_PRESENT) +DEFINE_SPINLOCK(zs_lock); + struct dec_zschannel zs_channels[NUM_CHANNELS]; struct dec_serial zs_soft[NUM_CHANNELS]; int zs_channels_found; @@ -159,8 +161,6 @@ static unsigned char zs_init_regs[16] __initdata = { 0 /* write 15 */ }; -DECLARE_TASK_QUEUE(tq_zs_serial); - static struct tty_driver *serial_driver; /* serial subtype definitions */ @@ -294,8 +294,7 @@ static inline void zs_rtsdtr(struct dec_serial *info, int which, int set) { unsigned long flags; - - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (info->zs_channel != info->zs_chan_a) { if (set) { info->zs_chan_a->curregs[5] |= (which & (RTS | DTR)); @@ -304,7 +303,7 @@ static inline void zs_rtsdtr(struct dec_serial *info, int which, int set) } write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* Utility routines for the Zilog */ @@ -345,12 +344,10 @@ static inline void rs_recv_clear(struct dec_zschannel *zsc) * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */ -static _INLINE_ void rs_sched_event(struct dec_serial *info, - int event) +static _INLINE_ void rs_sched_event(struct dec_serial *info, int event) { info->event |= 1 << event; - queue_task(&info->tqueue, &tq_zs_serial); - mark_bh(SERIAL_BH); + tasklet_schedule(&info->tlet); } static _INLINE_ void receive_chars(struct dec_serial *info, @@ -497,9 +494,10 @@ static _INLINE_ void status_handle(struct dec_serial *info) /* * This is the serial driver's generic interrupt routine */ -void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct dec_serial *info = (struct dec_serial *) dev_id; + irqreturn_t status = IRQ_NONE; unsigned char zs_intreg; int shift; @@ -521,6 +519,8 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) if ((zs_intreg & CHAN_IRQMASK) == 0) break; + status = IRQ_HANDLED; + if (zs_intreg & CHBRxIP) { receive_chars(info, regs); } @@ -534,6 +534,8 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* Why do we need this ? */ write_zsreg(info->zs_channel, 0, RES_H_IUS); + + return status; } #ifdef ZS_DEBUG_REGS @@ -578,12 +580,12 @@ static void rs_stop(struct tty_struct *tty) return; #if 1 - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (info->zs_channel->curregs[5] & TxENAB) { info->zs_channel->curregs[5] &= ~TxENAB; write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); #endif } @@ -595,7 +597,7 @@ static void rs_start(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_start")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); #if 1 if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) { info->zs_channel->curregs[5] |= TxENAB; @@ -606,7 +608,7 @@ static void rs_start(struct tty_struct *tty) transmit_chars(info); } #endif - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* @@ -618,12 +620,8 @@ static void rs_start(struct tty_struct *tty) * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_zs_serial); -} -static void do_softint(void *private_) +static void do_softint(unsigned long private_) { struct dec_serial *info = (struct dec_serial *) private_; struct tty_struct *tty; @@ -634,10 +632,11 @@ static void do_softint(void *private_) if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); } } -int zs_startup(struct dec_serial * info) +static int zs_startup(struct dec_serial * info) { unsigned long flags; @@ -650,7 +649,7 @@ int zs_startup(struct dec_serial * info) return -ENOMEM; } - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); #ifdef SERIAL_DEBUG_OPEN printk("starting up ttyS%d (irq %d)...", info->line, info->irq); @@ -706,7 +705,7 @@ int zs_startup(struct dec_serial * info) info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->flags |= ZILOG_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return 0; } @@ -726,7 +725,7 @@ static void shutdown(struct dec_serial * info) info->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave(&zs_lock, flags); if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); @@ -749,7 +748,7 @@ static void shutdown(struct dec_serial * info) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ZILOG_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* @@ -785,7 +784,7 @@ static void change_speed(struct dec_serial *info) i += 15; } - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); info->zs_baud = baud_table[i]; if (info->zs_baud) { brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor); @@ -858,7 +857,7 @@ static void change_speed(struct dec_serial *info) /* Load up the new values */ load_zsregs(info->zs_channel, info->zs_channel->curregs); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } static void rs_flush_chars(struct tty_struct *tty) @@ -874,9 +873,9 @@ static void rs_flush_chars(struct tty_struct *tty) return; /* Enable transmitter */ - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); transmit_chars(info); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } static int rs_write(struct tty_struct * tty, @@ -892,26 +891,17 @@ static int rs_write(struct tty_struct * tty, if (!tty || !info->xmit_buf) return 0; - save_flags(flags); while (1) { - cli(); + spin_lock_irqsave(&zs_lock, flags); c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; - if (from_user) { - down(&tmp_buf_sem); - copy_from_user(tmp_buf, buf, c); - c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - up(&tmp_buf_sem); - } else - memcpy(info->xmit_buf + info->xmit_head, buf, c); + memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt += c; - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); buf += c; count -= c; total += c; @@ -920,7 +910,7 @@ static int rs_write(struct tty_struct * tty, if (info->xmit_cnt && !tty->stopped && !info->tx_stopped && !info->tx_active) transmit_chars(info); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return total; } @@ -952,9 +942,9 @@ static void rs_flush_buffer(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) return; - cli(); + spin_lock_irq(&zs_lock); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); + spin_unlock_irq(&zs_lock); tty_wakeup(tty); } @@ -982,11 +972,11 @@ static void rs_throttle(struct tty_struct * tty) return; if (I_IXOFF(tty)) { - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); info->x_char = STOP_CHAR(tty); if (!info->tx_active) transmit_chars(info); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } if (C_CRTSCTS(tty)) { @@ -1010,7 +1000,7 @@ static void rs_unthrottle(struct tty_struct * tty) return; if (I_IXOFF(tty)) { - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (info->x_char) info->x_char = 0; else { @@ -1018,7 +1008,7 @@ static void rs_unthrottle(struct tty_struct * tty) if (!info->tx_active) transmit_chars(info); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } if (C_CRTSCTS(tty)) { @@ -1111,9 +1101,9 @@ static int get_lsr_info(struct dec_serial * info, unsigned int *value) { unsigned char status; - cli(); + spin_lock(&zs_lock); status = read_zsreg(info->zs_channel, 0); - sti(); + spin_unlock_irq(&zs_lock); put_user(status,value); return 0; } @@ -1136,11 +1126,11 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file) if (info->zs_channel == info->zs_chan_a) result = 0; else { - cli(); + spin_lock(&zs_lock); control = info->zs_chan_a->curregs[5]; status_a = read_zsreg(info->zs_chan_a, 0); status_b = read_zsreg(info->zs_channel, 0); - sti(); + spin_unlock_irq(&zs_lock); result = ((control & RTS) ? TIOCM_RTS: 0) | ((control & DTR) ? TIOCM_DTR: 0) | ((status_b & DCD) ? TIOCM_CAR: 0) @@ -1155,8 +1145,6 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct dec_serial * info = (struct dec_serial *)tty->driver_data; - int error; - unsigned int arg, bits; if (info->hook) return -ENODEV; @@ -1170,8 +1158,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, if (info->zs_channel == info->zs_chan_a) return 0; - get_user(arg, value); - cli(); + spin_lock(&zs_lock); if (set & TIOCM_RTS) info->zs_chan_a->curregs[5] |= RTS; if (set & TIOCM_DTR) @@ -1181,7 +1168,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, if (clear & TIOCM_DTR) info->zs_chan_a->curregs[5] &= ~DTR; write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); - sti(); + spin_unlock_irq(&zs_lock); return 0; } @@ -1198,19 +1185,18 @@ static void rs_break(struct tty_struct *tty, int break_state) if (!info->port) return; - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (break_state == -1) info->zs_channel->curregs[5] |= SND_BRK; else info->zs_channel->curregs[5] &= ~SND_BRK; write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct dec_serial * info = (struct dec_serial *)tty->driver_data; if (info->hook) @@ -1287,10 +1273,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return; } @@ -1315,7 +1301,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) info->count = 0; } if (info->count) { - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return; } info->flags |= ZILOG_CLOSING; @@ -1358,7 +1344,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* @@ -1398,7 +1384,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) /* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */ -void rs_hangup(struct tty_struct *tty) +static void rs_hangup(struct tty_struct *tty) { struct dec_serial * info = (struct dec_serial *)tty->driver_data; @@ -1466,16 +1452,16 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready before block: ttyS%d, count = %d\n", info->line, info->count); #endif - cli(); + spin_lock(&zs_lock); if (!tty_hung_up_p(filp)) info->count--; - sti(); + spin_unlock_irq(&zs_lock); info->blocked_open++; while (1) { - cli(); + spin_lock(&zs_lock); if (tty->termios->c_cflag & CBAUD) zs_rtsdtr(info, RTS | DTR, 1); - sti(); + spin_unlock_irq(&zs_lock); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { @@ -1523,7 +1509,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */ -int rs_open(struct tty_struct *tty, struct file * filp) +static int rs_open(struct tty_struct *tty, struct file * filp) { struct dec_serial *info; int retval, line; @@ -1706,7 +1692,7 @@ static void __init probe_sccs(void) } } - save_and_cli(flags); + spin_lock_irqsave(&zs_lock, flags); for (n = 0; n < zs_channels_found; n++) { if (n % 2 == 0) { write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES); @@ -1716,7 +1702,7 @@ static void __init probe_sccs(void) load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } static struct tty_operations serial_ops = { @@ -1749,9 +1735,6 @@ int __init zs_init(void) if(!BUS_PRESENT) return -ENODEV; - /* Setup base handler, and timer table. */ - init_bh(SERIAL_BH, do_serial_bh); - /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) probe_sccs(); @@ -1800,8 +1783,7 @@ int __init zs_init(void) info->event = 0; info->count = 0; info->blocked_open = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; + tasklet_init(&info->tlet, do_softint, (unsigned long)info); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n", @@ -1833,8 +1815,7 @@ int __init zs_init(void) /* * polling I/O routines */ -static int -zs_poll_tx_char(void *handle, unsigned char ch) +static int zs_poll_tx_char(void *handle, unsigned char ch) { struct dec_serial *info = handle; struct dec_zschannel *chan = info->zs_channel; @@ -1857,8 +1838,7 @@ zs_poll_tx_char(void *handle, unsigned char ch) return -ENODEV; } -static int -zs_poll_rx_char(void *handle) +static int zs_poll_rx_char(void *handle) { struct dec_serial *info = handle; struct dec_zschannel *chan = info->zs_channel; @@ -2037,7 +2017,7 @@ static int __init serial_console_setup(struct console *co, char *options) } co->cflag = cflag; - save_and_cli(flags); + spin_lock_irqsave(&zs_lock, flags); /* * Set up the baud rate generator. @@ -2092,7 +2072,7 @@ static int __init serial_console_setup(struct console *co, char *options) zs_soft[co->index].clk_divisor = clk_divisor; zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return 0; } @@ -2229,5 +2209,3 @@ void __init zs_kgdb_hook(int tty_num) set_debug_traps(); /* init stub */ } #endif /* ifdef CONFIG_KGDB */ - - diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h index c52edffa604..13512200ceb 100644 --- a/drivers/tc/zs.h +++ b/drivers/tc/zs.h @@ -6,14 +6,14 @@ * * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2004 Maciej W. Rozycki + * Copyright (C) 2004, 2005 Maciej W. Rozycki */ #ifndef _DECSERIAL_H #define _DECSERIAL_H #include -#define NUM_ZSREGS 16 +#define NUM_ZSREGS 16 struct serial_struct { int type; @@ -139,8 +139,7 @@ struct dec_serial { int xmit_head; int xmit_tail; int xmit_cnt; - struct tq_struct tqueue; - struct tq_struct tqueue_hangup; + struct tasklet_struct tlet; wait_queue_head_t open_wait; wait_queue_head_t close_wait; }; @@ -282,7 +281,7 @@ struct dec_serial { #define DLC 4 /* Disable Lower Chain */ #define MIE 8 /* Master Interrupt Enable */ #define STATHI 0x10 /* Status high */ -#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ +#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ #define NORESET 0 /* No reset on write to R9 */ #define CHRB 0x40 /* Reset channel B */ #define CHRA 0x80 /* Reset channel A */ @@ -395,8 +394,8 @@ struct dec_serial { /* Read Register 15 (value of WR 15) */ /* Misc macros */ -#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES)) -#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ +#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES)) +#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ garbage = read_zsdata(channel); \ garbage = read_zsdata(channel); \ garbage = read_zsdata(channel); \ -- cgit v1.2.3 From 4237f229018ccf937578dee97565a49d712809e8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 17 Nov 2005 16:23:50 +0000 Subject: [IDE] Add driver for Sibyte Swarm evaluation board This driver supports the IDE port on the Sibyte Swarm evaluation boards and it's relatives for the BCM1250 family of systems on a chip. Signed-off-by: Ralf Baechle Acked-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 4 + drivers/ide/Makefile | 2 +- drivers/ide/mips/Makefile | 1 + drivers/ide/mips/swarm.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 drivers/ide/mips/Makefile create mode 100644 drivers/ide/mips/swarm.c (limited to 'drivers') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 42e5b8175cb..ed2bc87f475 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -787,6 +787,10 @@ config BLK_DEV_IDE_PMAC_BLINK This option enables the use of the sleep LED as a hard drive activity LED. +config BLK_DEV_IDE_SWARM + tristate "IDE for Sibyte evaluation boards" + depends on SIBYTE_SB1xxx_SOC + config BLK_DEV_IDE_AU1XXX bool "IDE for AMD Alchemy Au1200" depends on SOC_AU1200 diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index cca9c075966..569fae71750 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -48,6 +48,6 @@ obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o -obj-$(CONFIG_BLK_DEV_IDE) += legacy/ arm/ +obj-$(CONFIG_BLK_DEV_IDE) += legacy/ arm/ mips/ obj-$(CONFIG_BLK_DEV_HD) += legacy/ obj-$(CONFIG_ETRAX_IDE) += cris/ diff --git a/drivers/ide/mips/Makefile b/drivers/ide/mips/Makefile new file mode 100644 index 00000000000..578e52a5958 --- /dev/null +++ b/drivers/ide/mips/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_BLK_DEV_IDE_SWARM) += swarm.o diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c new file mode 100644 index 00000000000..66f6064f464 --- /dev/null +++ b/drivers/ide/mips/swarm.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2001, 2002, 2003 Broadcom Corporation + * Copyright (C) 2004 MontaVista Software Inc. + * Author: Manish Lachwani, mlachwani@mvista.com + * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved. + * Author: Maciej W. Rozycki + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Derived loosely from ide-pmac.c, so: + * Copyright (C) 1998 Paul Mackerras. + * Copyright (C) 1995-1998 Mark Lord + */ + +/* + * Boards with SiByte processors so far have supported IDE devices via + * the Generic Bus, PCI bus, and built-in PCMCIA interface. In all + * cases, byte-swapping must be avoided for these devices (whereas + * other PCI devices, for example, will require swapping). Any + * SiByte-targetted kernel including IDE support will include this + * file. Probing of a Generic Bus for an IDE device is controlled by + * the definition of "SIBYTE_HAVE_IDE", which is provided by + * for Broadcom boards. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define DRV_NAME "ide-swarm" + +static char swarm_ide_string[] = DRV_NAME; + +static struct resource swarm_ide_resource = { + .name = "SWARM GenBus IDE", + .flags = IORESOURCE_MEM, +}; + +static struct platform_device *swarm_ide_dev; + +/* + * swarm_ide_probe - if the board header indicates the existence of + * Generic Bus IDE, allocate a HWIF for it. + */ +static int __devinit swarm_ide_probe(struct device *dev) +{ + ide_hwif_t *hwif; + u8 __iomem *base; + phys_t offset, size; + int i; + + if (!SIBYTE_HAVE_IDE) + return -ENODEV; + + /* Find an empty slot. */ + for (i = 0; i < MAX_HWIFS; i++) + if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) + break; + if (i >= MAX_HWIFS) { + printk(KERN_ERR DRV_NAME ": no free slot for interface\n"); + return -ENOMEM; + } + + hwif = ide_hwifs + i; + + base = ioremap(A_IO_EXT_BASE, 0x800); + offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)); + size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS)); + iounmap(base); + + offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE; + size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE; + if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) { + printk(KERN_INFO DRV_NAME + ": IDE interface at GenBus disabled\n"); + return -EBUSY; + } + + printk(KERN_INFO DRV_NAME ": IDE interface at GenBus slot %i\n", + IDE_CS); + + swarm_ide_resource.start = offset; + swarm_ide_resource.end = offset + size - 1; + if (request_resource(&iomem_resource, &swarm_ide_resource)) { + printk(KERN_ERR DRV_NAME + ": can't request I/O memory resource\n"); + return -EBUSY; + } + + base = ioremap(offset, size); + + /* Setup MMIO ops. */ + default_hwif_mmiops(hwif); + /* Prevent resource map manipulation. */ + hwif->mmio = 2; + hwif->noprobe = 0; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) + hwif->hw.io_ports[i] = + (unsigned long)(base + ((0x1f0 + i) << 5)); + hwif->hw.io_ports[IDE_CONTROL_OFFSET] = + (unsigned long)(base + (0x3f6 << 5)); + hwif->hw.irq = K_INT_GB_IDE; + + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + hwif->irq = hwif->hw.irq; + + dev_set_drvdata(dev, hwif); + + return 0; +} + +static struct device_driver swarm_ide_driver = { + .name = swarm_ide_string, + .bus = &platform_bus_type, + .probe = swarm_ide_probe, +}; + +static void swarm_ide_platform_release(struct device *device) +{ + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device(device); + kfree(pldev); +} + +static int __devinit swarm_ide_init_module(void) +{ + struct platform_device *pldev; + int err; + + printk(KERN_INFO "SWARM IDE driver\n"); + + if (driver_register(&swarm_ide_driver)) { + printk(KERN_ERR "Driver registration failed\n"); + err = -ENODEV; + goto out; + } + + if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) { + err = -ENOMEM; + goto out_unregister_driver; + } + + memset (pldev, 0, sizeof (*pldev)); + pldev->name = swarm_ide_string; + pldev->id = 0; + pldev->dev.release = swarm_ide_platform_release; + + if (platform_device_register(pldev)) { + err = -ENODEV; + goto out_free_pldev; + } + + if (!pldev->dev.driver) { + /* + * The driver was not bound to this device, there was + * no hardware at this address. Unregister it, as the + * release fuction will take care of freeing the + * allocated structure + */ + platform_device_unregister (pldev); + } + + swarm_ide_dev = pldev; + + return 0; + +out_free_pldev: + kfree(pldev); + +out_unregister_driver: + driver_unregister(&swarm_ide_driver); +out: + return err; +} + +module_init(swarm_ide_init_module); -- cgit v1.2.3