diff options
author | Felix Fietkau <nbd@openwrt.org> | 2007-09-06 16:27:37 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2007-09-06 16:27:37 +0000 |
commit | 56231056ea784f1cec6450f649b1adaed1f56366 (patch) | |
tree | 7b130d72d854cde2bcd3af8b11bd0f7be3dbff6a /target/linux/sibyte | |
parent | e1184aaa1a7a5e5eeef8e072bf0ea98c291be22a (diff) | |
download | upstream-56231056ea784f1cec6450f649b1adaed1f56366.tar.gz upstream-56231056ea784f1cec6450f649b1adaed1f56366.tar.bz2 upstream-56231056ea784f1cec6450f649b1adaed1f56366.zip |
strip the kernel version suffix from target directories, except for brcm-2.4 (the -2.4 will be included in the board name here). CONFIG_LINUX_<ver>_<board> becomes CONFIG_TARGET_<board>, same for profiles.
SVN-Revision: 8653
Diffstat (limited to 'target/linux/sibyte')
-rw-r--r-- | target/linux/sibyte/Makefile | 21 | ||||
-rw-r--r-- | target/linux/sibyte/base-files/default/etc/config/network | 14 | ||||
-rw-r--r-- | target/linux/sibyte/base-files/default/etc/inittab | 5 | ||||
-rw-r--r-- | target/linux/sibyte/config/default | 319 | ||||
-rw-r--r-- | target/linux/sibyte/image/Makefile | 37 | ||||
-rw-r--r-- | target/linux/sibyte/patches/000-DUART.patch | 1025 |
6 files changed, 1421 insertions, 0 deletions
diff --git a/target/linux/sibyte/Makefile b/target/linux/sibyte/Makefile new file mode 100644 index 0000000000..35cdb37f2e --- /dev/null +++ b/target/linux/sibyte/Makefile @@ -0,0 +1,21 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +ARCH:=mips +BOARD:=sibyte +BOARDNAME:=SiByte MIPS +FEATURES:=broken + +LINUX_VERSION:=2.6.21.5 + +include $(INCLUDE_DIR)/kernel-build.mk + +# include the profiles +-include profiles/*.mk + +$(eval $(call BuildKernel)) diff --git a/target/linux/sibyte/base-files/default/etc/config/network b/target/linux/sibyte/base-files/default/etc/config/network new file mode 100644 index 0000000000..9b65652f06 --- /dev/null +++ b/target/linux/sibyte/base-files/default/etc/config/network @@ -0,0 +1,14 @@ +# Copyright (C) 2006 OpenWrt.org + +config interface loopback + option ifname lo + option proto static + option ipaddr 127.0.0.1 + option netmask 255.0.0.0 + +config interface lan + option type bridge + option ifname "eth0 ath0" + option proto static + option ipaddr 192.168.1.1 + option netmask 255.255.255.0 diff --git a/target/linux/sibyte/base-files/default/etc/inittab b/target/linux/sibyte/base-files/default/etc/inittab new file mode 100644 index 0000000000..a6f4e17f01 --- /dev/null +++ b/target/linux/sibyte/base-files/default/etc/inittab @@ -0,0 +1,5 @@ +# Copyright (C) 2006 OpenWrt.org + +::sysinit:/etc/init.d/rcS +duart/0::askfirst:/bin/ash --login +#tts/1::askfirst:/bin/ash --login diff --git a/target/linux/sibyte/config/default b/target/linux/sibyte/config/default new file mode 100644 index 0000000000..bf33d13ac6 --- /dev/null +++ b/target/linux/sibyte/config/default @@ -0,0 +1,319 @@ +# CONFIG_32BIT is not set +CONFIG_64BIT=y +# CONFIG_ARPD is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_AU1000_UART is not set +CONFIG_BASE_SMALL=0 +CONFIG_BINFMT_ELF32=y +CONFIG_BLK_DEV_RAM_COUNT=16 +# CONFIG_BONDING is not set +CONFIG_BOOT_ELF32=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BT is not set +CONFIG_BUILD_ELF64=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +# CONFIG_CIFS_STATS is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_CLS_U32_PERF is not set +CONFIG_COMPAT=y +# CONFIG_COMPUTONE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_CONNECTOR=m +CONFIG_CPUSETS=y +CONFIG_CPU_BIG_ENDIAN=y +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_CPU_HAS_SYNC=y +# CONFIG_CPU_LITTLE_ENDIAN is not set +# CONFIG_CPU_MIPS32_R1 is not set +# CONFIG_CPU_MIPS32_R2 is not set +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +CONFIG_CPU_SB1=y +# CONFIG_CPU_SB1_PASS_1 is not set +# CONFIG_CPU_SB1_PASS_2_112x is not set +# CONFIG_CPU_SB1_PASS_2_1250 is not set +# CONFIG_CPU_SB1_PASS_2_2 is not set +# CONFIG_CPU_SB1_PASS_3 is not set +CONFIG_CPU_SB1_PASS_4=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CRC32C is not set +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CYCLADES is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DM9000 is not set +CONFIG_DMA_COHERENT=y +CONFIG_FW_LOADER=m +# CONFIG_GEN_RTC is not set +# CONFIG_HERMES is not set +# CONFIG_HID is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +CONFIG_HW_HAS_PCI=y +CONFIG_HW_RANDOM=m +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_1024 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_256 is not set +# CONFIG_HZ_48 is not set +# CONFIG_I2C is not set +# CONFIG_IDE is not set +# CONFIG_IKCONFIG is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INITRAMFS_ROOT_GID=0 +CONFIG_INITRAMFS_ROOT_UID=0 +CONFIG_INITRAMFS_SOURCE="../root" +CONFIG_INPUT=m +# CONFIG_IOSCHED_NOOP is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_POLICY is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_LOG is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_DSCP=m +# CONFIG_IP_NF_MATCH_HASHLIMIT is not set +CONFIG_IP_NF_MATCH_MULTIPORT=m +# CONFIG_IP_NF_MATCH_POLICY is not set +CONFIG_IP_NF_TARGET_DSCP=m +# CONFIG_IP_NF_TARGET_LOG is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_SAME is not set +# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_ISI is not set +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_LIBCRC32C is not set +# CONFIG_LLC2 is not set +CONFIG_LOCK_KERNEL=y +CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_MACH_ALCHEMY is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_VR41XX is not set +CONFIG_MINI_FO=m +CONFIG_MIPS=y +CONFIG_MIPS32_COMPAT=y +# CONFIG_MIPS32_N32 is not set +CONFIG_MIPS32_O32=y +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1200 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_IVR is not set +CONFIG_MIPS_L1_CACHE_SHIFT=5 +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_MT is not set +# CONFIG_MIPS_MTX1 is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1200 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MIPS_XXS1500 is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_MOXA_SMARTIO_NEW is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_BLKMTD is not set +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_AMDSTD_RETRY=0 +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_CHAR=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_ONENAND is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_IPGRE_BROADCAST is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_PKTGEN is not set +CONFIG_NET_SB1250_MAC=y +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_NETDEV_1000=y +CONFIG_NR_CPUS=2 +# CONFIG_NTFS_FS is not set +# CONFIG_N_HDLC is not set +CONFIG_OBSOLETE_INTERMODULE=y +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_PAGE_SIZE_16KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PCMCIA is not set +# CONFIG_PCCARD is not set +# CONFIG_PCI_LEGACY_PROC is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PREEMPT_BKL is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_KCORE is not set +# CONFIG_RELAYFS_FS is not set +# CONFIG_RIO is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_RTC is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_SB1XXX_CORELIS is not set +# CONFIG_SB1_CERR_STALL is not set +# CONFIG_SB1_CEX_ALWAYS_FATAL is not set +# CONFIG_SCSI is not set +# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_BUS_WATCHER is not set +# CONFIG_SIBYTE_CARMEL is not set +CONFIG_SIBYTE_CFE=y +CONFIG_SIBYTE_CFE_CONSOLE=y +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_DMA_PAGEOPS is not set +CONFIG_SIBYTE_HAS_LDT=y +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_PTSWARM is not set +# CONFIG_SIBYTE_RHONE is not set +CONFIG_SIBYTE_SB1250=y +CONFIG_SIBYTE_SB1250_DUART=y +CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y +# CONFIG_SIBYTE_SB1250_PROF is not set +CONFIG_SIBYTE_SB1xxx_SOC=y +# CONFIG_SIBYTE_SENTOSA is not set +CONFIG_SIBYTE_SWARM=y +# CONFIG_SIBYTE_TBPROF is not set +# CONFIG_SIMULATION is not set +CONFIG_SMP=y +# CONFIG_SOUND is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPECIALIX is not set +# CONFIG_STALDRV is not set +CONFIG_STOP_MACHINE=y +CONFIG_SWAP_IO_SPACE=y +# CONFIG_SX is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_SYNCLINK_GT is not set +CONFIG_SYS_HAS_CPU_SB1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y +CONFIG_SYS_SUPPORTS_HIGHMEM=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +# CONFIG_TELCLOCK is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_TOSHIBA_RBTX4938 is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_USB is not set +# CONFIG_WATCHDOG is not set diff --git a/target/linux/sibyte/image/Makefile b/target/linux/sibyte/image/Makefile new file mode 100644 index 0000000000..fbff86deda --- /dev/null +++ b/target/linux/sibyte/image/Makefile @@ -0,0 +1,37 @@ +# +# Copyright (C) 2007 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +#define Image/Prepare +# cp $(LINUX_DIR)/arch/arm/boot/zImage $(KDIR)/zImage +#endef + +define Image/BuildKernel + cp $(KDIR)/vmlinux $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-vmlinux +endef + +define Image/Build + $(call Image/Build/$(1),$(1)) +endef + +define Image/Build/jffs2-64k + dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img bs=65536 conv=sync +endef + +define Image/Build/jffs2-128k + dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img bs=131072 conv=sync + $(call Image/Build/slug,$(1)) +endef + +define Image/Build/squashfs + $(call prepare_generic_squashfs,$(KDIR)/root.squashfs) + dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img bs=131072 conv=sync + $(call Image/Build/slug,$(1)) +endef + +$(eval $(call BuildImage)) diff --git a/target/linux/sibyte/patches/000-DUART.patch b/target/linux/sibyte/patches/000-DUART.patch new file mode 100644 index 0000000000..468d9dface --- /dev/null +++ b/target/linux/sibyte/patches/000-DUART.patch @@ -0,0 +1,1025 @@ +diff -Nur linux-2.6.21.1/drivers/char/Kconfig linux-2.6.21.1-owrt/drivers/char/Kconfig +--- linux-2.6.21.1/drivers/char/Kconfig 2007-04-27 23:49:26.000000000 +0200 ++++ linux-2.6.21.1-owrt/drivers/char/Kconfig 2007-05-24 22:28:54.000000000 +0200 +@@ -386,6 +386,14 @@ + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use a console on a serial port, say Y. Otherwise, say N. + ++config SIBYTE_SB1250_DUART ++ bool "Support for BCM1xxx onchip DUART" ++ depends on MIPS && SIBYTE_SB1xxx_SOC=y ++ ++config SIBYTE_SB1250_DUART_CONSOLE ++ bool "Console on BCM1xxx DUART" ++ depends on SIBYTE_SB1250_DUART ++ + config SERIAL_DEC + bool "DECstation serial support" + depends on MACH_DECSTATION +diff -Nur linux-2.6.21.1/drivers/char/Makefile linux-2.6.21.1-owrt/drivers/char/Makefile +--- linux-2.6.21.1/drivers/char/Makefile 2007-04-27 23:49:26.000000000 +0200 ++++ linux-2.6.21.1-owrt/drivers/char/Makefile 2007-05-24 22:32:31.000000000 +0200 +@@ -32,6 +32,7 @@ + obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o + obj-$(CONFIG_MOXA_SMARTIO) += mxser.o + obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o ++obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o + obj-$(CONFIG_COMPUTONE) += ip2/ + obj-$(CONFIG_RISCOM8) += riscom8.o + obj-$(CONFIG_ISI) += isicom.o +diff -Nur linux-2.6.21.1/drivers/char/sb1250_duart.c linux-2.6.21.1-owrt/drivers/char/sb1250_duart.c +--- linux-2.6.21.1/drivers/char/sb1250_duart.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.21.1-owrt/drivers/char/sb1250_duart.c 2007-05-24 22:10:12.000000000 +0200 +@@ -0,0 +1,979 @@ ++/* ++ * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation ++ * ++ * 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. ++ */ ++ ++/* ++ * Driver support for the on-chip sb1250 dual-channel serial port, ++ * running in asynchronous mode. Also, support for doing a serial console ++ * on one of those ports ++ */ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/serial.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/console.h> ++#include <linux/kdev_t.h> ++#include <linux/major.h> ++#include <linux/termios.h> ++#include <linux/spinlock.h> ++#include <linux/irq.h> ++#include <linux/errno.h> ++#include <linux/tty.h> ++#include <linux/sched.h> ++#include <linux/tty_flip.h> ++#include <linux/timer.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <asm/delay.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/sibyte/swarm.h> ++#include <asm/sibyte/sb1250.h> ++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) ++#include <asm/sibyte/bcm1480_regs.h> ++#include <asm/sibyte/bcm1480_int.h> ++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) ++#include <asm/sibyte/sb1250_regs.h> ++#include <asm/sibyte/sb1250_int.h> ++#else ++#error invalid SiByte UART configuation ++#endif ++#include <asm/sibyte/sb1250_uart.h> ++#include <asm/war.h> ++ ++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) ++#define UNIT_CHANREG(n,reg) A_BCM1480_DUART_CHANREG((n),(reg)) ++#define UNIT_IMRREG(n) A_BCM1480_DUART_IMRREG(n) ++#define UNIT_INT(n) (K_BCM1480_INT_UART_0 + (n)) ++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) ++#define UNIT_CHANREG(n,reg) A_DUART_CHANREG((n),(reg)) ++#define UNIT_IMRREG(n) A_DUART_IMRREG(n) ++#define UNIT_INT(n) (K_INT_UART_0 + (n)) ++#else ++#error invalid SiByte UART configuation ++#endif ++ ++/* Toggle spewing of debugging output */ ++#undef DEBUG ++ ++#define DEFAULT_CFLAGS (CS8 | B115200) ++ ++#define TX_INTEN 1 ++#define DUART_INITIALIZED 2 ++ ++#define DUART_MAX_LINE 4 ++char sb1250_duart_present[DUART_MAX_LINE]; ++EXPORT_SYMBOL(sb1250_duart_present); ++ ++/* ++ * In bug 1956, we get glitches that can mess up uart registers. This ++ * "read-mode-reg after any register access" is an accepted workaround. ++ */ ++#if SIBYTE_1956_WAR ++# define SB1_SER1956_WAR { \ ++ u32 ignore; \ ++ ignore = csr_in32(uart_states[line].mode_1); \ ++ ignore = csr_in32(uart_states[line].mode_2); \ ++ } ++#else ++# define SB1_SER1956_WAR ++#endif ++ ++/* ++ * Still not sure what the termios structures set up here are for, ++ * but we have to supply pointers to them to register the tty driver ++ */ ++static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver; ++ ++/* ++ * This lock protects both the open flags for all the uart states as ++ * well as the reference count for the module ++ */ ++static DEFINE_SPINLOCK(open_lock); ++ ++typedef struct { ++ unsigned char outp_buf[SERIAL_XMIT_SIZE]; ++ unsigned int outp_head; ++ unsigned int outp_tail; ++ unsigned int outp_count; ++ spinlock_t outp_lock; ++ unsigned int open; ++ unsigned int line; ++ unsigned int last_cflags; ++ unsigned long flags; ++ struct tty_struct *tty; ++ ++ /* CSR addresses */ ++ unsigned int *status; ++ unsigned int *imr; ++ unsigned int *tx_hold; ++ unsigned int *rx_hold; ++ unsigned int *mode_1; ++ unsigned int *mode_2; ++ unsigned int *clk_sel; ++ unsigned int *cmd; ++} uart_state_t; ++ ++static uart_state_t uart_states[DUART_MAX_LINE]; ++ ++/* ++ * Inline functions local to this module ++ */ ++ ++static inline u32 READ_SERCSR(volatile u32 *addr, int line) ++{ ++ u32 val = csr_in32(addr); ++ SB1_SER1956_WAR; ++ return val; ++} ++ ++static inline void WRITE_SERCSR(u32 val, volatile u32 *addr, int line) ++{ ++ csr_out32(val, addr); ++ SB1_SER1956_WAR; ++} ++ ++static void init_duart_port(uart_state_t *port, int line) ++{ ++ if (!(port->flags & DUART_INITIALIZED)) { ++ port->line = line; ++ port->status = IOADDR(UNIT_CHANREG(line, R_DUART_STATUS)); ++ port->imr = IOADDR(UNIT_IMRREG(line)); ++ port->tx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_TX_HOLD)); ++ port->rx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_RX_HOLD)); ++ port->mode_1 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_1)); ++ port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2)); ++ port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL)); ++ port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD)); ++ port->last_cflags = DEFAULT_CFLAGS; ++ spin_lock_init(&port->outp_lock); ++ port->flags |= DUART_INITIALIZED; ++ } ++} ++ ++/* ++ * Mask out the passed interrupt lines at the duart level. This should be ++ * called while holding the associated outp_lock. ++ */ ++static inline void duart_mask_ints(unsigned int line, unsigned int mask) ++{ ++ uart_state_t *port = uart_states + line; ++ u64 tmp = READ_SERCSR(port->imr, line); ++ WRITE_SERCSR(tmp & ~mask, port->imr, line); ++} ++ ++ ++/* Unmask the passed interrupt lines at the duart level */ ++static inline void duart_unmask_ints(unsigned int line, unsigned int mask) ++{ ++ uart_state_t *port = uart_states + line; ++ u64 tmp = READ_SERCSR(port->imr, line); ++ WRITE_SERCSR(tmp | mask, port->imr, line); ++} ++ ++static inline void transmit_char_pio(uart_state_t *us) ++{ ++ struct tty_struct *tty = us->tty; ++ int blocked = 0; ++ ++ if (spin_trylock(&us->outp_lock)) { ++ for (;;) { ++ if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY)) ++ break; ++ if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) { ++ break; ++ } else { ++ WRITE_SERCSR(us->outp_buf[us->outp_head], ++ us->tx_hold, us->line); ++ us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1); ++ if (--us->outp_count <= 0) ++ break; ++ } ++ udelay(10); ++ } ++ spin_unlock(&us->outp_lock); ++ } else { ++ blocked = 1; ++ } ++ ++ if (!us->outp_count || tty->stopped || ++ tty->hw_stopped || blocked) { ++ us->flags &= ~TX_INTEN; ++ duart_mask_ints(us->line, M_DUART_IMR_TX); ++ } ++ ++ if (us->open && ++ (us->outp_count < (SERIAL_XMIT_SIZE/2))) { ++ /* ++ * We told the discipline at one point that we had no ++ * space, so it went to sleep. Wake it up when we hit ++ * half empty ++ */ ++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && ++ tty->ldisc.write_wakeup) ++ tty->ldisc.write_wakeup(tty); ++ wake_up_interruptible(&tty->write_wait); ++ } ++} ++ ++/* ++ * Generic interrupt handler for both channels. dev_id is a pointer ++ * to the proper uart_states structure, so from that we can derive ++ * which port interrupted ++ */ ++ ++static irqreturn_t duart_int(int irq, void *dev_id) ++{ ++ uart_state_t *us = (uart_state_t *)dev_id; ++ struct tty_struct *tty = us->tty; ++ unsigned int status = READ_SERCSR(us->status, us->line); ++ ++ pr_debug("DUART INT\n"); ++ ++ if (status & M_DUART_RX_RDY) { ++ int counter = 2048; ++ unsigned int ch; ++ ++ if (status & M_DUART_OVRUN_ERR) ++ tty_insert_flip_char(tty, 0, TTY_OVERRUN); ++ if (status & M_DUART_PARITY_ERR) { ++ printk("Parity error!\n"); ++ } else if (status & M_DUART_FRM_ERR) { ++ printk("Frame error!\n"); ++ } ++ ++ while (counter > 0) { ++ if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY)) ++ break; ++ ch = READ_SERCSR(us->rx_hold, us->line); ++ tty_insert_flip_char(tty, ch, 0); ++ udelay(1); ++ counter--; ++ } ++ tty_flip_buffer_push(tty); ++ } ++ ++ if (status & M_DUART_TX_RDY) { ++ transmit_char_pio(us); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Actual driver functions ++ */ ++ ++/* Return the number of characters we can accomodate in a write at this instant */ ++static int duart_write_room(struct tty_struct *tty) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ int retval; ++ ++ retval = SERIAL_XMIT_SIZE - us->outp_count; ++ ++ pr_debug("duart_write_room called, returning %i\n", retval); ++ ++ return retval; ++} ++ ++/* memcpy the data from src to destination, but take extra care if the ++ data is coming from user space */ ++static inline int copy_buf(char *dest, const char *src, int size, int from_user) ++{ ++ if (from_user) { ++ (void) copy_from_user(dest, src, size); ++ } else { ++ memcpy(dest, src, size); ++ } ++ return size; ++} ++ ++/* ++ * Buffer up to count characters from buf to be written. If we don't have ++ * other characters buffered, enable the tx interrupt to start sending ++ */ ++static int duart_write(struct tty_struct *tty, const unsigned char *buf, ++ int count) ++{ ++ uart_state_t *us; ++ int c, t, total = 0; ++ unsigned long flags; ++ ++ if (!tty) return 0; ++ ++ us = tty->driver_data; ++ if (!us) return 0; ++ ++ pr_debug("duart_write called for %i chars by %i (%s)\n", count, ++ current->pid, current->comm); ++ ++ spin_lock_irqsave(&us->outp_lock, flags); ++ ++ for (;;) { ++ c = count; ++ ++ t = SERIAL_XMIT_SIZE - us->outp_tail; ++ if (t < c) c = t; ++ ++ t = SERIAL_XMIT_SIZE - 1 - us->outp_count; ++ if (t < c) c = t; ++ ++ if (c <= 0) break; ++ ++ memcpy(us->outp_buf + us->outp_tail, buf, c); ++ ++ us->outp_count += c; ++ us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1); ++ buf += c; ++ count -= c; ++ total += c; ++ } ++ ++ spin_unlock_irqrestore(&us->outp_lock, flags); ++ ++ if (us->outp_count && !tty->stopped && ++ !tty->hw_stopped && !(us->flags & TX_INTEN)) { ++ us->flags |= TX_INTEN; ++ duart_unmask_ints(us->line, M_DUART_IMR_TX); ++ } ++ ++ return total; ++} ++ ++ ++/* Buffer one character to be written. If there's not room for it, just drop ++ it on the floor. This is used for echo, among other things */ ++static void duart_put_char(struct tty_struct *tty, u_char ch) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ unsigned long flags; ++ ++ pr_debug("duart_put_char called. Char is %x (%c)\n", (int)ch, ch); ++ ++ spin_lock_irqsave(&us->outp_lock, flags); ++ ++ if (us->outp_count == SERIAL_XMIT_SIZE) { ++ spin_unlock_irqrestore(&us->outp_lock, flags); ++ return; ++ } ++ ++ us->outp_buf[us->outp_tail] = ch; ++ us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1); ++ us->outp_count++; ++ ++ spin_unlock_irqrestore(&us->outp_lock, flags); ++} ++ ++static void duart_flush_chars(struct tty_struct * tty) ++{ ++ uart_state_t *port; ++ ++ if (!tty) ++ return; ++ ++ port = tty->driver_data; ++ ++ if (!port) ++ return; ++ ++ if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) { ++ return; ++ } ++ ++ port->flags |= TX_INTEN; ++ duart_unmask_ints(port->line, M_DUART_IMR_TX); ++} ++ ++/* Return the number of characters in the output buffer that have yet to be ++ written */ ++static int duart_chars_in_buffer(struct tty_struct *tty) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ int retval; ++ ++ retval = us->outp_count; ++ ++ pr_debug("duart_chars_in_buffer returning %i\n", retval); ++ ++ return retval; ++} ++ ++/* Kill everything we haven't yet shoved into the FIFO. Turn off the ++ transmit interrupt since we've nothing more to transmit */ ++static void duart_flush_buffer(struct tty_struct *tty) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ unsigned long flags; ++ ++ pr_debug("duart_flush_buffer called\n"); ++ spin_lock_irqsave(&us->outp_lock, flags); ++ us->outp_head = us->outp_tail = us->outp_count = 0; ++ spin_unlock_irqrestore(&us->outp_lock, flags); ++ ++ wake_up_interruptible(&us->tty->write_wait); ++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && ++ tty->ldisc.write_wakeup) ++ tty->ldisc.write_wakeup(tty); ++} ++ ++ ++/* See sb1250 user manual for details on these registers */ ++static inline void duart_set_cflag(unsigned int line, unsigned int cflag) ++{ ++ unsigned int mode_reg1 = 0, mode_reg2 = 0; ++ unsigned int clk_divisor; ++ uart_state_t *port = uart_states + line; ++ ++ switch (cflag & CSIZE) { ++ case CS7: ++ mode_reg1 |= V_DUART_BITS_PER_CHAR_7; ++ ++ default: ++ /* We don't handle CS5 or CS6...is there a way we're supposed to ++ * flag this? right now we just force them to CS8 */ ++ mode_reg1 |= 0x0; ++ break; ++ } ++ if (cflag & CSTOPB) { ++ mode_reg2 |= M_DUART_STOP_BIT_LEN_2; ++ } ++ if (!(cflag & PARENB)) { ++ mode_reg1 |= V_DUART_PARITY_MODE_NONE; ++ } ++ if (cflag & PARODD) { ++ mode_reg1 |= M_DUART_PARITY_TYPE_ODD; ++ } ++ ++ /* Formula for this is (5000000/baud)-1, but we saturate ++ at 12 bits, which means we can't actually do anything less ++ that 1200 baud */ ++ switch (cflag & CBAUD) { ++ case B200: ++ case B300: ++ case B1200: clk_divisor = 4095; break; ++ case B1800: clk_divisor = 2776; break; ++ case B2400: clk_divisor = 2082; break; ++ case B4800: clk_divisor = 1040; break; ++ case B9600: clk_divisor = 519; break; ++ case B19200: clk_divisor = 259; break; ++ case B38400: clk_divisor = 129; break; ++ default: ++ case B57600: clk_divisor = 85; break; ++ case B115200: clk_divisor = 42; break; ++ } ++ WRITE_SERCSR(mode_reg1, port->mode_1, port->line); ++ WRITE_SERCSR(mode_reg2, port->mode_2, port->line); ++ WRITE_SERCSR(clk_divisor, port->clk_sel, port->line); ++ port->last_cflags = cflag; ++} ++ ++ ++/* Handle notification of a termios change. */ ++static void duart_set_termios(struct tty_struct *tty, struct termios *old) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ ++ pr_debug("duart_set_termios called by %i (%s)\n", current->pid, ++ current->comm); ++ if (old && tty->termios->c_cflag == old->c_cflag) ++ return; ++ duart_set_cflag(us->line, tty->termios->c_cflag); ++} ++ ++static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) ++{ ++ struct serial_struct tmp; ++ ++ memset(&tmp, 0, sizeof(tmp)); ++ ++ tmp.type = PORT_SB1250; ++ tmp.line = us->line; ++ tmp.port = UNIT_CHANREG(tmp.line,0); ++ tmp.irq = UNIT_INT(tmp.line); ++ tmp.xmit_fifo_size = 16; /* fixed by hw */ ++ tmp.baud_base = 5000000; ++ tmp.io_type = SERIAL_IO_MEM; ++ ++ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static int duart_ioctl(struct tty_struct *tty, struct file * file, ++ unsigned int cmd, unsigned long arg) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ ++/* if (serial_paranoia_check(info, tty->device, "rs_ioctl")) ++ return -ENODEV;*/ ++ switch (cmd) { ++ case TIOCMGET: ++ printk("Ignoring TIOCMGET\n"); ++ break; ++ case TIOCMBIS: ++ printk("Ignoring TIOCMBIS\n"); ++ break; ++ case TIOCMBIC: ++ printk("Ignoring TIOCMBIC\n"); ++ break; ++ case TIOCMSET: ++ printk("Ignoring TIOCMSET\n"); ++ break; ++ case TIOCGSERIAL: ++ return get_serial_info(us,(struct serial_struct *) arg); ++ case TIOCSSERIAL: ++ printk("Ignoring TIOCSSERIAL\n"); ++ break; ++ case TIOCSERCONFIG: ++ printk("Ignoring TIOCSERCONFIG\n"); ++ break; ++ case TIOCSERGETLSR: /* Get line status register */ ++ printk("Ignoring TIOCSERGETLSR\n"); ++ break; ++ case TIOCSERGSTRUCT: ++ printk("Ignoring TIOCSERGSTRUCT\n"); ++ break; ++ case TIOCMIWAIT: ++ printk("Ignoring TIOCMIWAIT\n"); ++ break; ++ case TIOCGICOUNT: ++ printk("Ignoring TIOCGICOUNT\n"); ++ break; ++ case TIOCSERGWILD: ++ printk("Ignoring TIOCSERGWILD\n"); ++ break; ++ case TIOCSERSWILD: ++ printk("Ignoring TIOCSERSWILD\n"); ++ break; ++ default: ++ break; ++ } ++// printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm); ++ return -ENOIOCTLCMD; ++} ++ ++/* XXXKW locking? */ ++static void duart_start(struct tty_struct *tty) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ ++ pr_debug("duart_start called\n"); ++ ++ if (us->outp_count && !(us->flags & TX_INTEN)) { ++ us->flags |= TX_INTEN; ++ duart_unmask_ints(us->line, M_DUART_IMR_TX); ++ } ++} ++ ++/* XXXKW locking? */ ++static void duart_stop(struct tty_struct *tty) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ ++ pr_debug("duart_stop called\n"); ++ ++ if (us->outp_count && (us->flags & TX_INTEN)) { ++ us->flags &= ~TX_INTEN; ++ duart_mask_ints(us->line, M_DUART_IMR_TX); ++ } ++} ++ ++/* Not sure on the semantics of this; are we supposed to wait until the stuff ++ * already in the hardware FIFO drains, or are we supposed to wait until ++ * we've drained the output buffer, too? I'm assuming the former, 'cause thats ++ * what the other drivers seem to assume ++ */ ++ ++static void duart_wait_until_sent(struct tty_struct *tty, int timeout) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ unsigned long orig_jiffies; ++ ++ orig_jiffies = jiffies; ++ pr_debug("duart_wait_until_sent(%d)+\n", timeout); ++ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ if (signal_pending(current)) ++ break; ++ if (timeout && time_after(jiffies, orig_jiffies + timeout)) ++ break; ++ } ++ pr_debug("duart_wait_until_sent()-\n"); ++} ++ ++/* ++ * duart_hangup() --- called by tty_hangup() when a hangup is signaled. ++ */ ++static void duart_hangup(struct tty_struct *tty) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ ++ duart_flush_buffer(tty); ++ us->open = 0; ++ us->tty = 0; ++} ++ ++/* ++ * Open a tty line. Note that this can be called multiple times, so ->open can ++ * be >1. Only set up the tty struct if this is a "new" open, e.g. ->open was ++ * zero ++ */ ++static int duart_open(struct tty_struct *tty, struct file *filp) ++{ ++ uart_state_t *us; ++ unsigned int line = tty->index; ++ unsigned long flags; ++ ++ if ((line >= tty->driver->num) || !sb1250_duart_present[line]) ++ return -ENODEV; ++ ++ pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n", ++ current->pid, current->comm, tty, (void *)&tty->read_wait, ++ (void *)&tty->write_wait); ++ ++ us = uart_states + line; ++ tty->driver_data = us; ++ ++ spin_lock_irqsave(&open_lock, flags); ++ if (!us->open) { ++ us->tty = tty; ++ us->tty->termios->c_cflag = us->last_cflags; ++ } ++ us->open++; ++ us->flags &= ~TX_INTEN; ++ duart_unmask_ints(line, M_DUART_IMR_RX); ++ spin_unlock_irqrestore(&open_lock, flags); ++ ++ return 0; ++} ++ ++ ++/* ++ * Close a reference count out. If reference count hits zero, null the ++ * tty, kill the interrupts. The tty_io driver is responsible for making ++ * sure we've cleared out our internal buffers before calling close() ++ */ ++static void duart_close(struct tty_struct *tty, struct file *filp) ++{ ++ uart_state_t *us = (uart_state_t *) tty->driver_data; ++ unsigned long flags; ++ ++ pr_debug("duart_close called by %i (%s)\n", current->pid, current->comm); ++ ++ if (!us || !us->open) ++ return; ++ ++ spin_lock_irqsave(&open_lock, flags); ++ if (tty_hung_up_p(filp)) { ++ spin_unlock_irqrestore(&open_lock, flags); ++ return; ++ } ++ ++ if (--us->open < 0) { ++ us->open = 0; ++ printk(KERN_ERR "duart: bad open count: %d\n", us->open); ++ } ++ if (us->open) { ++ spin_unlock_irqrestore(&open_lock, flags); ++ return; ++ } ++ ++ spin_unlock_irqrestore(&open_lock, flags); ++ ++ tty->closing = 1; ++ ++ /* Stop accepting input */ ++ duart_mask_ints(us->line, M_DUART_IMR_RX); ++ /* Wait for FIFO to drain */ ++ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) ++ ; ++ ++ if (tty->driver->flush_buffer) ++ tty->driver->flush_buffer(tty); ++ if (tty->ldisc.flush_buffer) ++ tty->ldisc.flush_buffer(tty); ++ tty->closing = 0; ++} ++ ++ ++static struct tty_operations duart_ops = { ++ .open = duart_open, ++ .close = duart_close, ++ .write = duart_write, ++ .put_char = duart_put_char, ++ .flush_chars = duart_flush_chars, ++ .write_room = duart_write_room, ++ .chars_in_buffer = duart_chars_in_buffer, ++ .flush_buffer = duart_flush_buffer, ++ .ioctl = duart_ioctl, ++// .throttle = duart_throttle, ++// .unthrottle = duart_unthrottle, ++ .set_termios = duart_set_termios, ++ .stop = duart_stop, ++ .start = duart_start, ++ .hangup = duart_hangup, ++ .wait_until_sent = duart_wait_until_sent, ++}; ++ ++/* Initialize the sb1250_duart_present array based on SOC type. */ ++static void __init sb1250_duart_init_present_lines(void) ++{ ++ int i, max_lines; ++ ++ /* Set the number of available units based on the SOC type. */ ++ switch (soc_type) { ++ case K_SYS_SOC_TYPE_BCM1x55: ++ case K_SYS_SOC_TYPE_BCM1x80: ++ max_lines = 4; ++ break; ++ default: ++ /* Assume at least two serial ports at the normal address. */ ++ max_lines = 2; ++ break; ++ } ++ if (max_lines > DUART_MAX_LINE) ++ max_lines = DUART_MAX_LINE; ++ ++ for (i = 0; i < max_lines; i++) ++ sb1250_duart_present[i] = 1; ++} ++ ++/* Set up the driver and register it, register the UART interrupts. This ++ is called from tty_init, or as a part of the module init */ ++static int __init sb1250_duart_init(void) ++{ ++ int i; ++ ++ sb1250_duart_init_present_lines(); ++ ++ sb1250_duart_driver = alloc_tty_driver(DUART_MAX_LINE); ++ if (!sb1250_duart_driver) ++ return -ENOMEM; ++ ++ sb1250_duart_driver->owner = THIS_MODULE; ++ sb1250_duart_driver->name = "duart"; ++ sb1250_duart_driver->major = TTY_MAJOR; ++ sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE; ++ sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL; ++ sb1250_duart_driver->subtype = SERIAL_TYPE_NORMAL; ++ sb1250_duart_driver->init_termios = tty_std_termios; ++ sb1250_duart_driver->flags = TTY_DRIVER_REAL_RAW; ++ tty_set_operations(sb1250_duart_driver, &duart_ops); ++ ++ for (i = 0; i < DUART_MAX_LINE; i++) { ++ uart_state_t *port = uart_states + i; ++ ++ if (!sb1250_duart_present[i]) ++ continue; ++ ++ init_duart_port(port, i); ++ duart_mask_ints(i, M_DUART_IMR_ALL); ++ if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) { ++ panic("Couldn't get uart0 interrupt line"); ++ } ++ /* ++ * this generic write to a register does not implement the 1956 ++ * WAR and sometimes output gets corrupted afterwards, ++ * especially if the port was in use as a console. ++ */ ++ __raw_writel(M_DUART_RX_EN|M_DUART_TX_EN, port->cmd); ++ ++ /* ++ * we should really check to see if it's registered as a console ++ * before trashing those settings ++ */ ++ duart_set_cflag(i, port->last_cflags); ++ } ++ ++ /* Interrupts are now active, our ISR can be called. */ ++ ++ if (tty_register_driver(sb1250_duart_driver)) { ++ printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n"); ++ put_tty_driver(sb1250_duart_driver); ++ return 1; ++ } ++ return 0; ++} ++ ++/* Unload the driver. Unregister stuff, get ready to go away */ ++static void __exit sb1250_duart_fini(void) ++{ ++ unsigned long flags; ++ int i; ++ ++ local_irq_save(flags); ++ tty_unregister_driver(sb1250_duart_driver); ++ put_tty_driver(sb1250_duart_driver); ++ ++ for (i = 0; i < DUART_MAX_LINE; i++) { ++ if (!sb1250_duart_present[i]) ++ continue; ++ free_irq(UNIT_INT(i), &uart_states[i]); ++ disable_irq(UNIT_INT(i)); ++ } ++ local_irq_restore(flags); ++} ++ ++module_init(sb1250_duart_init); ++module_exit(sb1250_duart_fini); ++MODULE_DESCRIPTION("SB1250 Duart serial driver"); ++MODULE_AUTHOR("Broadcom Corp."); ++ ++#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE ++ ++/* ++ * Serial console stuff. Very basic, polling driver for doing serial ++ * console output. The console_sem is held by the caller, so we ++ * shouldn't be interrupted for more console activity. ++ * XXXKW What about getting interrupted by uart driver activity? ++ */ ++ ++void serial_outc(unsigned char c, int line) ++{ ++ uart_state_t *port = uart_states + line; ++ while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ; ++ WRITE_SERCSR(c, port->tx_hold, line); ++ while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ; ++} ++ ++static void ser_console_write(struct console *cons, const char *s, ++ unsigned int count) ++{ ++ int line = cons->index; ++ uart_state_t *port = uart_states + line; ++ u32 imr; ++ ++ imr = READ_SERCSR(port->imr, line); ++ WRITE_SERCSR(0, port->imr, line); ++ while (count--) { ++ if (*s == '\n') ++ serial_outc('\r', line); ++ serial_outc(*s++, line); ++ } ++ WRITE_SERCSR(imr, port->imr, line); ++} ++ ++static struct tty_driver *ser_console_device(struct console *c, int *index) ++{ ++ *index = c->index; ++ return sb1250_duart_driver; ++} ++ ++static int ser_console_setup(struct console *cons, char *str) ++{ ++ int i; ++ ++ sb1250_duart_init_present_lines(); ++ ++ for (i = 0; i < DUART_MAX_LINE; i++) { ++ uart_state_t *port = uart_states + i; ++ u32 cflags = DEFAULT_CFLAGS; ++ ++ if (!sb1250_duart_present[i]) ++ continue; ++ ++ init_duart_port(port, i); ++ if (str) { ++ int speed; ++ char par = 'n'; ++ int cbits = 8; ++ ++ cflags = 0; ++ ++ /* ++ * format is in Documentation/serial_console.txt ++ */ ++ sscanf(str, "%d%c%d", &speed, &par, &cbits); ++ ++ switch (speed) { ++ case 200: ++ case 300: ++ case 1200: ++ cflags |= B1200; ++ break; ++ case 1800: ++ cflags |= B1800; ++ break; ++ case 2400: ++ cflags |= B2400; ++ break; ++ case 4800: ++ cflags |= B4800; ++ break; ++ default: ++ case 9600: ++ cflags |= B9600; ++ break; ++ case 19200: ++ cflags |= B19200; ++ break; ++ case 38400: ++ cflags |= B38400; ++ break; ++ case 57600: ++ cflags |= B57600; ++ break; ++ case 115200: ++ cflags |= B115200; ++ break; ++ } ++ switch (par) { ++ case 'o': ++ cflags |= PARODD; ++ case 'e': ++ cflags |= PARENB; ++ } ++ switch (cbits) { ++ default: // we only do 7 or 8 ++ case 8: ++ cflags |= CS8; ++ break; ++ case 7: ++ cflags |= CS7; ++ break; ++ } ++ } ++ duart_set_cflag(i, cflags); ++ WRITE_SERCSR(M_DUART_RX_EN | M_DUART_TX_EN, port->cmd, i); ++ } ++ ++ return 0; ++} ++ ++static struct console sb1250_ser_cons = { ++ .name = "duart", ++ .write = ser_console_write, ++ .device = ser_console_device, ++ .setup = ser_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++}; ++ ++static int __init sb1250_serial_console_init(void) ++{ ++ //add_preferred_console("duart", 0, "57600n8"); ++ register_console(&sb1250_ser_cons); ++ return 0; ++} ++ ++console_initcall(sb1250_serial_console_init); ++ ++#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */ +diff -Nur linux-2.6.21.1/include/linux/serial.h linux-2.6.21.1-owrt/include/linux/serial.h +--- linux-2.6.21.1/include/linux/serial.h 2007-04-27 23:49:26.000000000 +0200 ++++ linux-2.6.21.1-owrt/include/linux/serial.h 2007-05-24 22:10:29.000000000 +0200 +@@ -76,7 +76,8 @@ + #define PORT_16654 11 + #define PORT_16850 12 + #define PORT_RSA 13 /* RSA-DV II/S card */ +-#define PORT_MAX 13 ++#define PORT_SB1250 14 ++#define PORT_MAX 14 + + #define SERIAL_IO_PORT 0 + #define SERIAL_IO_HUB6 1 |