(2006-08-06) rescue-bootcd

This commit is contained in:
2006-08-06 00:00:00 +02:00
parent 2f796b816a
commit decb062d20
21091 changed files with 7076462 additions and 0 deletions

View File

@@ -0,0 +1,287 @@
cmd_drivers/serial/8250.o := gcc -Wp,-MD,drivers/serial/.8250.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=8250 -DKBUILD_MODNAME=8250 -c -o drivers/serial/8250.o drivers/serial/8250.c
deps_drivers/serial/8250.o := \
drivers/serial/8250.c \
$(wildcard include/config/serial/8250/console.h) \
$(wildcard include/config/magic/sysrq.h) \
$(wildcard include/config/.h) \
$(wildcard include/config/serial/many/ports.h) \
$(wildcard include/config/serial/detect/irq.h) \
$(wildcard include/config/serial/multiport.h) \
$(wildcard include/config/hub6.h) \
$(wildcard include/config/serial/8250/detect/irq.h) \
$(wildcard include/config/serial/8250/multiport.h) \
$(wildcard include/config/serial/8250/many/ports.h) \
$(wildcard include/config/serial/8250/nr/uarts.h) \
$(wildcard include/config/serial/8250/rsa.h) \
$(wildcard include/config/ppc.h) \
$(wildcard include/config/mca.h) \
$(wildcard include/config/type.h) \
$(wildcard include/config/irq.h) \
include/linux/config.h \
$(wildcard include/config/h.h) \
include/linux/module.h \
$(wildcard include/config/modules.h) \
$(wildcard include/config/modversions.h) \
$(wildcard include/config/module/unload.h) \
$(wildcard include/config/kallsyms.h) \
include/linux/sched.h \
$(wildcard include/config/keys.h) \
$(wildcard include/config/schedstats.h) \
$(wildcard include/config/smp.h) \
$(wildcard include/config/numa.h) \
$(wildcard include/config/security.h) \
$(wildcard include/config/preempt.h) \
include/asm/param.h \
include/linux/capability.h \
include/linux/types.h \
$(wildcard include/config/uid16.h) \
include/linux/posix_types.h \
include/linux/stddef.h \
include/linux/compiler.h \
include/linux/compiler-gcc3.h \
include/linux/compiler-gcc.h \
include/asm/posix_types.h \
include/asm/types.h \
$(wildcard include/config/highmem64g.h) \
$(wildcard include/config/lbd.h) \
include/linux/spinlock.h \
$(wildcard include/config/debug/spinlock.h) \
$(wildcard include/config/lockmeter.h) \
include/linux/preempt.h \
include/linux/linkage.h \
include/asm/linkage.h \
$(wildcard include/config/regparm.h) \
$(wildcard include/config/x86/alignment/16.h) \
include/linux/thread_info.h \
include/linux/bitops.h \
include/asm/bitops.h \
include/asm/thread_info.h \
$(wildcard include/config/4kstacks.h) \
$(wildcard include/config/debug/stack/usage.h) \
include/asm/page.h \
$(wildcard include/config/x86/use/3dnow.h) \
$(wildcard include/config/x86/pae.h) \
$(wildcard include/config/hugetlb/page.h) \
$(wildcard include/config/highmem4g.h) \
$(wildcard include/config/discontigmem.h) \
include/asm/processor.h \
$(wildcard include/config/mk8.h) \
$(wildcard include/config/mk7.h) \
include/asm/vm86.h \
include/asm/math_emu.h \
include/asm/sigcontext.h \
include/asm/segment.h \
include/asm/cpufeature.h \
include/asm/msr.h \
include/asm/system.h \
$(wildcard include/config/x86/cmpxchg.h) \
$(wildcard include/config/x86/oostore.h) \
include/linux/kernel.h \
$(wildcard include/config/debug/spinlock/sleep.h) \
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
include/asm/byteorder.h \
$(wildcard include/config/x86/bswap.h) \
include/linux/byteorder/little_endian.h \
include/linux/byteorder/swab.h \
include/linux/byteorder/generic.h \
include/asm/bug.h \
include/asm-generic/bug.h \
include/linux/cache.h \
include/asm/cache.h \
$(wildcard include/config/x86/l1/cache/shift.h) \
include/linux/threads.h \
$(wildcard include/config/nr/cpus.h) \
include/asm/percpu.h \
include/asm-generic/percpu.h \
include/linux/stringify.h \
include/linux/timex.h \
$(wildcard include/config/time/interpolation.h) \
include/linux/time.h \
include/linux/seqlock.h \
include/asm/timex.h \
$(wildcard include/config/x86/elan.h) \
$(wildcard include/config/x86/tsc.h) \
$(wildcard include/config/x86/generic.h) \
include/linux/jiffies.h \
include/asm/div64.h \
include/linux/rbtree.h \
include/linux/cpumask.h \
$(wildcard include/config/hotplug/cpu.h) \
include/linux/bitmap.h \
include/linux/string.h \
include/asm/string.h \
include/asm/semaphore.h \
include/asm/atomic.h \
$(wildcard include/config/m386.h) \
include/linux/wait.h \
include/linux/list.h \
include/linux/prefetch.h \
include/asm/current.h \
include/linux/rwsem.h \
$(wildcard include/config/rwsem/generic/spinlock.h) \
include/asm/rwsem.h \
include/asm/ptrace.h \
$(wildcard include/config/frame/pointer.h) \
include/asm/mmu.h \
include/linux/smp.h \
include/linux/sem.h \
$(wildcard include/config/sysvipc.h) \
include/linux/ipc.h \
include/asm/ipcbuf.h \
include/asm/sembuf.h \
include/linux/signal.h \
include/asm/signal.h \
include/asm/siginfo.h \
include/asm-generic/siginfo.h \
include/linux/resource.h \
include/asm/resource.h \
include/linux/securebits.h \
include/linux/fs_struct.h \
include/linux/completion.h \
include/linux/pid.h \
include/linux/percpu.h \
include/linux/slab.h \
include/linux/gfp.h \
include/linux/mmzone.h \
$(wildcard include/config/force/max/zoneorder.h) \
include/linux/numa.h \
include/linux/topology.h \
$(wildcard include/config/sched/smt.h) \
include/asm/topology.h \
include/asm-generic/topology.h \
include/linux/init.h \
$(wildcard include/config/hotplug.h) \
include/linux/kmalloc_sizes.h \
$(wildcard include/config/mmu.h) \
$(wildcard include/config/large/allocs.h) \
include/linux/param.h \
include/linux/timer.h \
include/linux/aio.h \
include/linux/workqueue.h \
include/linux/aio_abi.h \
include/linux/stat.h \
include/asm/stat.h \
include/linux/kmod.h \
$(wildcard include/config/kmod.h) \
include/linux/errno.h \
include/asm/errno.h \
include/asm-generic/errno.h \
include/asm-generic/errno-base.h \
include/linux/elf.h \
include/asm/elf.h \
include/asm/user.h \
include/linux/utsname.h \
include/linux/kobject.h \
include/linux/sysfs.h \
$(wildcard include/config/sysfs.h) \
include/linux/kref.h \
include/linux/kobject_uevent.h \
$(wildcard include/config/kobject/uevent.h) \
include/linux/moduleparam.h \
include/asm/local.h \
include/asm/module.h \
$(wildcard include/config/m486.h) \
$(wildcard include/config/m586.h) \
$(wildcard include/config/m586tsc.h) \
$(wildcard include/config/m586mmx.h) \
$(wildcard include/config/m686.h) \
$(wildcard include/config/mpentiumii.h) \
$(wildcard include/config/mpentiumiii.h) \
$(wildcard include/config/mpentiumm.h) \
$(wildcard include/config/mpentium4.h) \
$(wildcard include/config/mk6.h) \
$(wildcard include/config/mcrusoe.h) \
$(wildcard include/config/mefficeon.h) \
$(wildcard include/config/mwinchipc6.h) \
$(wildcard include/config/mwinchip2.h) \
$(wildcard include/config/mwinchip3d.h) \
$(wildcard include/config/mcyrixiii.h) \
$(wildcard include/config/mviac3/2.h) \
include/linux/ioport.h \
include/linux/console.h \
include/linux/sysrq.h \
include/linux/delay.h \
include/asm/delay.h \
include/linux/device.h \
include/linux/pm.h \
$(wildcard include/config/pm.h) \
include/linux/tty.h \
$(wildcard include/config/legacy/pty/count.h) \
include/linux/fs.h \
$(wildcard include/config/dnotify.h) \
$(wildcard include/config/quota.h) \
$(wildcard include/config/epoll.h) \
$(wildcard include/config/auditsyscall.h) \
include/linux/limits.h \
include/linux/kdev_t.h \
include/linux/ioctl.h \
include/asm/ioctl.h \
include/linux/dcache.h \
include/linux/rcupdate.h \
include/linux/prio_tree.h \
include/linux/radix-tree.h \
include/linux/audit.h \
$(wildcard include/config/audit.h) \
include/linux/quota.h \
include/linux/dqblk_xfs.h \
include/linux/dqblk_v1.h \
include/linux/dqblk_v2.h \
include/linux/nfs_fs_i.h \
include/linux/nfs.h \
include/linux/sunrpc/msg_prot.h \
include/linux/fcntl.h \
include/asm/fcntl.h \
include/linux/err.h \
include/linux/major.h \
include/linux/termios.h \
include/asm/termios.h \
include/asm/termbits.h \
include/asm/ioctls.h \
include/linux/tty_driver.h \
include/linux/cdev.h \
include/linux/tty_ldisc.h \
include/linux/tty_flip.h \
include/linux/serial_reg.h \
include/linux/serial_core.h \
$(wildcard include/config/serial/core/console.h) \
$(wildcard include/config/hard/pps.h) \
include/linux/interrupt.h \
$(wildcard include/config/generic/hardirqs.h) \
$(wildcard include/config/generic/irq/probe.h) \
include/linux/hardirq.h \
include/linux/smp_lock.h \
$(wildcard include/config/lock/kernel.h) \
include/asm/hardirq.h \
include/linux/irq.h \
$(wildcard include/config/arch/s390.h) \
include/asm/irq.h \
$(wildcard include/config/x86/local/apic.h) \
$(wildcard include/config/irqbalance.h) \
include/asm-i386/mach-default/irq_vectors.h \
include/asm-i386/mach-default/irq_vectors_limits.h \
$(wildcard include/config/pci/msi.h) \
$(wildcard include/config/x86/io/apic.h) \
include/asm/hw_irq.h \
include/linux/profile.h \
$(wildcard include/config/proc/fs.h) \
$(wildcard include/config/profiling.h) \
include/asm/sections.h \
include/asm-generic/sections.h \
include/linux/irq_cpustat.h \
include/linux/circ_buf.h \
include/linux/serial.h \
include/linux/serial_8250.h \
include/asm/io.h \
$(wildcard include/config/x86/ppro/fence.h) \
$(wildcard include/config/x86/numaq.h) \
include/asm-generic/iomap.h \
include/linux/vmalloc.h \
drivers/serial/8250.h \
$(wildcard include/config/serial/8250/share/irq.h) \
$(wildcard include/config/pci.h) \
include/asm/serial.h \
drivers/serial/8250.o: $(deps_drivers/serial/8250.o)
$(deps_drivers/serial/8250.o):

View File

@@ -0,0 +1,307 @@
cmd_drivers/serial/8250_pci.o := gcc -Wp,-MD,drivers/serial/.8250_pci.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=8250_pci -DKBUILD_MODNAME=8250_pci -c -o drivers/serial/8250_pci.o drivers/serial/8250_pci.c
deps_drivers/serial/8250_pci.o := \
drivers/serial/8250_pci.c \
include/linux/module.h \
$(wildcard include/config/modules.h) \
$(wildcard include/config/modversions.h) \
$(wildcard include/config/module/unload.h) \
$(wildcard include/config/kallsyms.h) \
include/linux/config.h \
$(wildcard include/config/h.h) \
include/linux/sched.h \
$(wildcard include/config/keys.h) \
$(wildcard include/config/schedstats.h) \
$(wildcard include/config/smp.h) \
$(wildcard include/config/numa.h) \
$(wildcard include/config/security.h) \
$(wildcard include/config/preempt.h) \
$(wildcard include/config/magic/sysrq.h) \
include/asm/param.h \
include/linux/capability.h \
include/linux/types.h \
$(wildcard include/config/uid16.h) \
include/linux/posix_types.h \
include/linux/stddef.h \
include/linux/compiler.h \
include/linux/compiler-gcc3.h \
include/linux/compiler-gcc.h \
include/asm/posix_types.h \
include/asm/types.h \
$(wildcard include/config/highmem64g.h) \
$(wildcard include/config/lbd.h) \
include/linux/spinlock.h \
$(wildcard include/config/debug/spinlock.h) \
$(wildcard include/config/lockmeter.h) \
include/linux/preempt.h \
include/linux/linkage.h \
include/asm/linkage.h \
$(wildcard include/config/regparm.h) \
$(wildcard include/config/x86/alignment/16.h) \
include/linux/thread_info.h \
include/linux/bitops.h \
include/asm/bitops.h \
include/asm/thread_info.h \
$(wildcard include/config/4kstacks.h) \
$(wildcard include/config/debug/stack/usage.h) \
include/asm/page.h \
$(wildcard include/config/x86/use/3dnow.h) \
$(wildcard include/config/x86/pae.h) \
$(wildcard include/config/hugetlb/page.h) \
$(wildcard include/config/highmem4g.h) \
$(wildcard include/config/discontigmem.h) \
include/asm/processor.h \
$(wildcard include/config/mk8.h) \
$(wildcard include/config/mk7.h) \
include/asm/vm86.h \
include/asm/math_emu.h \
include/asm/sigcontext.h \
include/asm/segment.h \
include/asm/cpufeature.h \
include/asm/msr.h \
include/asm/system.h \
$(wildcard include/config/x86/cmpxchg.h) \
$(wildcard include/config/x86/oostore.h) \
include/linux/kernel.h \
$(wildcard include/config/debug/spinlock/sleep.h) \
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
include/asm/byteorder.h \
$(wildcard include/config/x86/bswap.h) \
include/linux/byteorder/little_endian.h \
include/linux/byteorder/swab.h \
include/linux/byteorder/generic.h \
include/asm/bug.h \
include/asm-generic/bug.h \
include/linux/cache.h \
include/asm/cache.h \
$(wildcard include/config/x86/l1/cache/shift.h) \
include/linux/threads.h \
$(wildcard include/config/nr/cpus.h) \
include/asm/percpu.h \
include/asm-generic/percpu.h \
include/linux/stringify.h \
include/linux/timex.h \
$(wildcard include/config/time/interpolation.h) \
include/linux/time.h \
include/linux/seqlock.h \
include/asm/timex.h \
$(wildcard include/config/x86/elan.h) \
$(wildcard include/config/x86/tsc.h) \
$(wildcard include/config/x86/generic.h) \
include/linux/jiffies.h \
include/asm/div64.h \
include/linux/rbtree.h \
include/linux/cpumask.h \
$(wildcard include/config/hotplug/cpu.h) \
include/linux/bitmap.h \
include/linux/string.h \
include/asm/string.h \
include/asm/semaphore.h \
include/asm/atomic.h \
$(wildcard include/config/m386.h) \
include/linux/wait.h \
include/linux/list.h \
include/linux/prefetch.h \
include/asm/current.h \
include/linux/rwsem.h \
$(wildcard include/config/rwsem/generic/spinlock.h) \
include/asm/rwsem.h \
include/asm/ptrace.h \
$(wildcard include/config/frame/pointer.h) \
include/asm/mmu.h \
include/linux/smp.h \
include/linux/sem.h \
$(wildcard include/config/sysvipc.h) \
include/linux/ipc.h \
include/asm/ipcbuf.h \
include/asm/sembuf.h \
include/linux/signal.h \
include/asm/signal.h \
include/asm/siginfo.h \
include/asm-generic/siginfo.h \
include/linux/resource.h \
include/asm/resource.h \
include/linux/securebits.h \
include/linux/fs_struct.h \
include/linux/completion.h \
include/linux/pid.h \
include/linux/percpu.h \
include/linux/slab.h \
$(wildcard include/config/.h) \
include/linux/gfp.h \
include/linux/mmzone.h \
$(wildcard include/config/force/max/zoneorder.h) \
include/linux/numa.h \
include/linux/topology.h \
$(wildcard include/config/sched/smt.h) \
include/asm/topology.h \
include/asm-generic/topology.h \
include/linux/init.h \
$(wildcard include/config/hotplug.h) \
include/linux/kmalloc_sizes.h \
$(wildcard include/config/mmu.h) \
$(wildcard include/config/large/allocs.h) \
include/linux/param.h \
include/linux/timer.h \
include/linux/aio.h \
include/linux/workqueue.h \
include/linux/aio_abi.h \
include/linux/stat.h \
include/asm/stat.h \
include/linux/kmod.h \
$(wildcard include/config/kmod.h) \
include/linux/errno.h \
include/asm/errno.h \
include/asm-generic/errno.h \
include/asm-generic/errno-base.h \
include/linux/elf.h \
include/asm/elf.h \
include/asm/user.h \
include/linux/utsname.h \
include/linux/kobject.h \
include/linux/sysfs.h \
$(wildcard include/config/sysfs.h) \
include/linux/kref.h \
include/linux/kobject_uevent.h \
$(wildcard include/config/kobject/uevent.h) \
include/linux/moduleparam.h \
include/asm/local.h \
include/asm/module.h \
$(wildcard include/config/m486.h) \
$(wildcard include/config/m586.h) \
$(wildcard include/config/m586tsc.h) \
$(wildcard include/config/m586mmx.h) \
$(wildcard include/config/m686.h) \
$(wildcard include/config/mpentiumii.h) \
$(wildcard include/config/mpentiumiii.h) \
$(wildcard include/config/mpentiumm.h) \
$(wildcard include/config/mpentium4.h) \
$(wildcard include/config/mk6.h) \
$(wildcard include/config/mcrusoe.h) \
$(wildcard include/config/mefficeon.h) \
$(wildcard include/config/mwinchipc6.h) \
$(wildcard include/config/mwinchip2.h) \
$(wildcard include/config/mwinchip3d.h) \
$(wildcard include/config/mcyrixiii.h) \
$(wildcard include/config/mviac3/2.h) \
include/linux/pci.h \
$(wildcard include/config/pci/names.h) \
$(wildcard include/config/pci.h) \
$(wildcard include/config/isa.h) \
$(wildcard include/config/eisa.h) \
$(wildcard include/config/pci/msi.h) \
$(wildcard include/config/pci/domains.h) \
include/linux/mod_devicetable.h \
include/linux/pci_ids.h \
include/linux/ioport.h \
include/linux/device.h \
include/linux/pm.h \
$(wildcard include/config/pm.h) \
include/linux/dmapool.h \
include/asm/io.h \
$(wildcard include/config/x86/ppro/fence.h) \
$(wildcard include/config/x86/numaq.h) \
include/asm-generic/iomap.h \
include/linux/vmalloc.h \
include/asm/scatterlist.h \
include/asm/pci.h \
include/linux/mm.h \
$(wildcard include/config/sysctl.h) \
$(wildcard include/config/stack/growsup.h) \
$(wildcard include/config/highmem.h) \
$(wildcard include/config/shmem.h) \
$(wildcard include/config/proc/fs.h) \
$(wildcard include/config/debug/pagealloc.h) \
$(wildcard include/config/arch/gate/area.h) \
include/linux/prio_tree.h \
include/linux/fs.h \
$(wildcard include/config/dnotify.h) \
$(wildcard include/config/quota.h) \
$(wildcard include/config/epoll.h) \
$(wildcard include/config/auditsyscall.h) \
include/linux/limits.h \
include/linux/kdev_t.h \
include/linux/ioctl.h \
include/asm/ioctl.h \
include/linux/dcache.h \
include/linux/rcupdate.h \
include/linux/radix-tree.h \
include/linux/audit.h \
$(wildcard include/config/audit.h) \
include/linux/quota.h \
include/linux/dqblk_xfs.h \
include/linux/dqblk_v1.h \
include/linux/dqblk_v2.h \
include/linux/nfs_fs_i.h \
include/linux/nfs.h \
include/linux/sunrpc/msg_prot.h \
include/linux/fcntl.h \
include/asm/fcntl.h \
include/linux/err.h \
include/asm/pgtable.h \
$(wildcard include/config/highpte.h) \
include/asm/fixmap.h \
$(wildcard include/config/x86/local/apic.h) \
$(wildcard include/config/x86/io/apic.h) \
$(wildcard include/config/x86/visws/apic.h) \
$(wildcard include/config/x86/f00f/bug.h) \
$(wildcard include/config/x86/cyclone/timer.h) \
$(wildcard include/config/acpi/boot.h) \
$(wildcard include/config/pci/mmconfig.h) \
include/asm/acpi.h \
$(wildcard include/config/acpi/pci.h) \
$(wildcard include/config/acpi/sleep.h) \
include/asm/apicdef.h \
include/asm/pgtable-2level-defs.h \
include/asm/pgtable-2level.h \
include/asm-generic/pgtable.h \
include/linux/page-flags.h \
$(wildcard include/config/swap.h) \
include/asm-generic/pci-dma-compat.h \
include/linux/dma-mapping.h \
include/asm/dma-mapping.h \
include/asm-generic/pci.h \
include/linux/delay.h \
include/asm/delay.h \
include/linux/tty.h \
$(wildcard include/config/legacy/pty/count.h) \
include/linux/major.h \
include/linux/termios.h \
include/asm/termios.h \
include/asm/termbits.h \
include/asm/ioctls.h \
include/linux/tty_driver.h \
include/linux/cdev.h \
include/linux/tty_ldisc.h \
include/linux/serial_core.h \
$(wildcard include/config/type.h) \
$(wildcard include/config/irq.h) \
$(wildcard include/config/serial/core/console.h) \
$(wildcard include/config/hard/pps.h) \
include/linux/interrupt.h \
$(wildcard include/config/generic/hardirqs.h) \
$(wildcard include/config/generic/irq/probe.h) \
include/linux/hardirq.h \
include/linux/smp_lock.h \
$(wildcard include/config/lock/kernel.h) \
include/asm/hardirq.h \
include/linux/irq.h \
$(wildcard include/config/arch/s390.h) \
include/asm/irq.h \
$(wildcard include/config/irqbalance.h) \
include/asm-i386/mach-default/irq_vectors.h \
include/asm-i386/mach-default/irq_vectors_limits.h \
include/asm/hw_irq.h \
include/linux/profile.h \
$(wildcard include/config/profiling.h) \
include/asm/sections.h \
include/asm-generic/sections.h \
include/linux/irq_cpustat.h \
include/linux/circ_buf.h \
include/linux/8250_pci.h \
drivers/serial/8250.h \
$(wildcard include/config/serial/8250/share/irq.h) \
drivers/serial/8250_pci.o: $(deps_drivers/serial/8250_pci.o)
$(deps_drivers/serial/8250_pci.o):

View File

@@ -0,0 +1,310 @@
cmd_drivers/serial/8250_pnp.o := gcc -Wp,-MD,drivers/serial/.8250_pnp.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=8250_pnp -DKBUILD_MODNAME=8250_pnp -c -o drivers/serial/8250_pnp.o drivers/serial/8250_pnp.c
deps_drivers/serial/8250_pnp.o := \
drivers/serial/8250_pnp.c \
include/linux/module.h \
$(wildcard include/config/modules.h) \
$(wildcard include/config/modversions.h) \
$(wildcard include/config/module/unload.h) \
$(wildcard include/config/kallsyms.h) \
include/linux/config.h \
$(wildcard include/config/h.h) \
include/linux/sched.h \
$(wildcard include/config/keys.h) \
$(wildcard include/config/schedstats.h) \
$(wildcard include/config/smp.h) \
$(wildcard include/config/numa.h) \
$(wildcard include/config/security.h) \
$(wildcard include/config/preempt.h) \
$(wildcard include/config/magic/sysrq.h) \
include/asm/param.h \
include/linux/capability.h \
include/linux/types.h \
$(wildcard include/config/uid16.h) \
include/linux/posix_types.h \
include/linux/stddef.h \
include/linux/compiler.h \
include/linux/compiler-gcc3.h \
include/linux/compiler-gcc.h \
include/asm/posix_types.h \
include/asm/types.h \
$(wildcard include/config/highmem64g.h) \
$(wildcard include/config/lbd.h) \
include/linux/spinlock.h \
$(wildcard include/config/debug/spinlock.h) \
$(wildcard include/config/lockmeter.h) \
include/linux/preempt.h \
include/linux/linkage.h \
include/asm/linkage.h \
$(wildcard include/config/regparm.h) \
$(wildcard include/config/x86/alignment/16.h) \
include/linux/thread_info.h \
include/linux/bitops.h \
include/asm/bitops.h \
include/asm/thread_info.h \
$(wildcard include/config/4kstacks.h) \
$(wildcard include/config/debug/stack/usage.h) \
include/asm/page.h \
$(wildcard include/config/x86/use/3dnow.h) \
$(wildcard include/config/x86/pae.h) \
$(wildcard include/config/hugetlb/page.h) \
$(wildcard include/config/highmem4g.h) \
$(wildcard include/config/discontigmem.h) \
include/asm/processor.h \
$(wildcard include/config/mk8.h) \
$(wildcard include/config/mk7.h) \
include/asm/vm86.h \
include/asm/math_emu.h \
include/asm/sigcontext.h \
include/asm/segment.h \
include/asm/cpufeature.h \
include/asm/msr.h \
include/asm/system.h \
$(wildcard include/config/x86/cmpxchg.h) \
$(wildcard include/config/x86/oostore.h) \
include/linux/kernel.h \
$(wildcard include/config/debug/spinlock/sleep.h) \
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
include/asm/byteorder.h \
$(wildcard include/config/x86/bswap.h) \
include/linux/byteorder/little_endian.h \
include/linux/byteorder/swab.h \
include/linux/byteorder/generic.h \
include/asm/bug.h \
include/asm-generic/bug.h \
include/linux/cache.h \
include/asm/cache.h \
$(wildcard include/config/x86/l1/cache/shift.h) \
include/linux/threads.h \
$(wildcard include/config/nr/cpus.h) \
include/asm/percpu.h \
include/asm-generic/percpu.h \
include/linux/stringify.h \
include/linux/timex.h \
$(wildcard include/config/time/interpolation.h) \
include/linux/time.h \
include/linux/seqlock.h \
include/asm/timex.h \
$(wildcard include/config/x86/elan.h) \
$(wildcard include/config/x86/tsc.h) \
$(wildcard include/config/x86/generic.h) \
include/linux/jiffies.h \
include/asm/div64.h \
include/linux/rbtree.h \
include/linux/cpumask.h \
$(wildcard include/config/hotplug/cpu.h) \
include/linux/bitmap.h \
include/linux/string.h \
include/asm/string.h \
include/asm/semaphore.h \
include/asm/atomic.h \
$(wildcard include/config/m386.h) \
include/linux/wait.h \
include/linux/list.h \
include/linux/prefetch.h \
include/asm/current.h \
include/linux/rwsem.h \
$(wildcard include/config/rwsem/generic/spinlock.h) \
include/asm/rwsem.h \
include/asm/ptrace.h \
$(wildcard include/config/frame/pointer.h) \
include/asm/mmu.h \
include/linux/smp.h \
include/linux/sem.h \
$(wildcard include/config/sysvipc.h) \
include/linux/ipc.h \
include/asm/ipcbuf.h \
include/asm/sembuf.h \
include/linux/signal.h \
include/asm/signal.h \
include/asm/siginfo.h \
include/asm-generic/siginfo.h \
include/linux/resource.h \
include/asm/resource.h \
include/linux/securebits.h \
include/linux/fs_struct.h \
include/linux/completion.h \
include/linux/pid.h \
include/linux/percpu.h \
include/linux/slab.h \
$(wildcard include/config/.h) \
include/linux/gfp.h \
include/linux/mmzone.h \
$(wildcard include/config/force/max/zoneorder.h) \
include/linux/numa.h \
include/linux/topology.h \
$(wildcard include/config/sched/smt.h) \
include/asm/topology.h \
include/asm-generic/topology.h \
include/linux/init.h \
$(wildcard include/config/hotplug.h) \
include/linux/kmalloc_sizes.h \
$(wildcard include/config/mmu.h) \
$(wildcard include/config/large/allocs.h) \
include/linux/param.h \
include/linux/timer.h \
include/linux/aio.h \
include/linux/workqueue.h \
include/linux/aio_abi.h \
include/linux/stat.h \
include/asm/stat.h \
include/linux/kmod.h \
$(wildcard include/config/kmod.h) \
include/linux/errno.h \
include/asm/errno.h \
include/asm-generic/errno.h \
include/asm-generic/errno-base.h \
include/linux/elf.h \
include/asm/elf.h \
include/asm/user.h \
include/linux/utsname.h \
include/linux/kobject.h \
include/linux/sysfs.h \
$(wildcard include/config/sysfs.h) \
include/linux/kref.h \
include/linux/kobject_uevent.h \
$(wildcard include/config/kobject/uevent.h) \
include/linux/moduleparam.h \
include/asm/local.h \
include/asm/module.h \
$(wildcard include/config/m486.h) \
$(wildcard include/config/m586.h) \
$(wildcard include/config/m586tsc.h) \
$(wildcard include/config/m586mmx.h) \
$(wildcard include/config/m686.h) \
$(wildcard include/config/mpentiumii.h) \
$(wildcard include/config/mpentiumiii.h) \
$(wildcard include/config/mpentiumm.h) \
$(wildcard include/config/mpentium4.h) \
$(wildcard include/config/mk6.h) \
$(wildcard include/config/mcrusoe.h) \
$(wildcard include/config/mefficeon.h) \
$(wildcard include/config/mwinchipc6.h) \
$(wildcard include/config/mwinchip2.h) \
$(wildcard include/config/mwinchip3d.h) \
$(wildcard include/config/mcyrixiii.h) \
$(wildcard include/config/mviac3/2.h) \
include/linux/pci.h \
$(wildcard include/config/pci/names.h) \
$(wildcard include/config/pci.h) \
$(wildcard include/config/isa.h) \
$(wildcard include/config/eisa.h) \
$(wildcard include/config/pci/msi.h) \
$(wildcard include/config/pci/domains.h) \
include/linux/mod_devicetable.h \
include/linux/pci_ids.h \
include/linux/ioport.h \
include/linux/device.h \
include/linux/pm.h \
$(wildcard include/config/pm.h) \
include/linux/dmapool.h \
include/asm/io.h \
$(wildcard include/config/x86/ppro/fence.h) \
$(wildcard include/config/x86/numaq.h) \
include/asm-generic/iomap.h \
include/linux/vmalloc.h \
include/asm/scatterlist.h \
include/asm/pci.h \
include/linux/mm.h \
$(wildcard include/config/sysctl.h) \
$(wildcard include/config/stack/growsup.h) \
$(wildcard include/config/highmem.h) \
$(wildcard include/config/shmem.h) \
$(wildcard include/config/proc/fs.h) \
$(wildcard include/config/debug/pagealloc.h) \
$(wildcard include/config/arch/gate/area.h) \
include/linux/prio_tree.h \
include/linux/fs.h \
$(wildcard include/config/dnotify.h) \
$(wildcard include/config/quota.h) \
$(wildcard include/config/epoll.h) \
$(wildcard include/config/auditsyscall.h) \
include/linux/limits.h \
include/linux/kdev_t.h \
include/linux/ioctl.h \
include/asm/ioctl.h \
include/linux/dcache.h \
include/linux/rcupdate.h \
include/linux/radix-tree.h \
include/linux/audit.h \
$(wildcard include/config/audit.h) \
include/linux/quota.h \
include/linux/dqblk_xfs.h \
include/linux/dqblk_v1.h \
include/linux/dqblk_v2.h \
include/linux/nfs_fs_i.h \
include/linux/nfs.h \
include/linux/sunrpc/msg_prot.h \
include/linux/fcntl.h \
include/asm/fcntl.h \
include/linux/err.h \
include/asm/pgtable.h \
$(wildcard include/config/highpte.h) \
include/asm/fixmap.h \
$(wildcard include/config/x86/local/apic.h) \
$(wildcard include/config/x86/io/apic.h) \
$(wildcard include/config/x86/visws/apic.h) \
$(wildcard include/config/x86/f00f/bug.h) \
$(wildcard include/config/x86/cyclone/timer.h) \
$(wildcard include/config/acpi/boot.h) \
$(wildcard include/config/pci/mmconfig.h) \
include/asm/acpi.h \
$(wildcard include/config/acpi/pci.h) \
$(wildcard include/config/acpi/sleep.h) \
include/asm/apicdef.h \
include/asm/pgtable-2level-defs.h \
include/asm/pgtable-2level.h \
include/asm-generic/pgtable.h \
include/linux/page-flags.h \
$(wildcard include/config/swap.h) \
include/asm-generic/pci-dma-compat.h \
include/linux/dma-mapping.h \
include/asm/dma-mapping.h \
include/asm-generic/pci.h \
include/linux/pnp.h \
$(wildcard include/config/normal.h) \
$(wildcard include/config/force.h) \
$(wildcard include/config/isapnp.h) \
$(wildcard include/config/pnpbios.h) \
$(wildcard include/config/pnp.h) \
include/linux/serial_core.h \
$(wildcard include/config/type.h) \
$(wildcard include/config/irq.h) \
$(wildcard include/config/serial/core/console.h) \
$(wildcard include/config/hard/pps.h) \
include/linux/interrupt.h \
$(wildcard include/config/generic/hardirqs.h) \
$(wildcard include/config/generic/irq/probe.h) \
include/linux/hardirq.h \
include/linux/smp_lock.h \
$(wildcard include/config/lock/kernel.h) \
include/asm/hardirq.h \
include/linux/irq.h \
$(wildcard include/config/arch/s390.h) \
include/asm/irq.h \
$(wildcard include/config/irqbalance.h) \
include/asm-i386/mach-default/irq_vectors.h \
include/asm-i386/mach-default/irq_vectors_limits.h \
include/asm/hw_irq.h \
include/linux/profile.h \
$(wildcard include/config/profiling.h) \
include/asm/sections.h \
include/asm-generic/sections.h \
include/linux/irq_cpustat.h \
include/linux/circ_buf.h \
include/linux/tty.h \
$(wildcard include/config/legacy/pty/count.h) \
include/linux/major.h \
include/linux/termios.h \
include/asm/termios.h \
include/asm/termbits.h \
include/asm/ioctls.h \
include/linux/tty_driver.h \
include/linux/cdev.h \
include/linux/tty_ldisc.h \
drivers/serial/8250.h \
$(wildcard include/config/serial/8250/share/irq.h) \
drivers/serial/8250_pnp.o: $(deps_drivers/serial/8250_pnp.o)
$(deps_drivers/serial/8250_pnp.o):

View File

@@ -0,0 +1 @@
cmd_drivers/serial/built-in.o := ld -m elf_i386 -r -o drivers/serial/built-in.o drivers/serial/serial_core.o drivers/serial/8250.o drivers/serial/8250_pci.o drivers/serial/8250_pnp.o

View File

@@ -0,0 +1,265 @@
cmd_drivers/serial/serial_core.o := gcc -Wp,-MD,drivers/serial/.serial_core.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=serial_core -DKBUILD_MODNAME=serial_core -c -o drivers/serial/serial_core.o drivers/serial/serial_core.c
deps_drivers/serial/serial_core.o := \
drivers/serial/serial_core.c \
$(wildcard include/config/serial/core/console.h) \
$(wildcard include/config/type.h) \
$(wildcard include/config/irq.h) \
$(wildcard include/config/proc/fs.h) \
include/linux/config.h \
$(wildcard include/config/h.h) \
include/linux/module.h \
$(wildcard include/config/modules.h) \
$(wildcard include/config/modversions.h) \
$(wildcard include/config/module/unload.h) \
$(wildcard include/config/kallsyms.h) \
include/linux/sched.h \
$(wildcard include/config/keys.h) \
$(wildcard include/config/schedstats.h) \
$(wildcard include/config/smp.h) \
$(wildcard include/config/numa.h) \
$(wildcard include/config/security.h) \
$(wildcard include/config/preempt.h) \
$(wildcard include/config/magic/sysrq.h) \
include/asm/param.h \
include/linux/capability.h \
include/linux/types.h \
$(wildcard include/config/uid16.h) \
include/linux/posix_types.h \
include/linux/stddef.h \
include/linux/compiler.h \
include/linux/compiler-gcc3.h \
include/linux/compiler-gcc.h \
include/asm/posix_types.h \
include/asm/types.h \
$(wildcard include/config/highmem64g.h) \
$(wildcard include/config/lbd.h) \
include/linux/spinlock.h \
$(wildcard include/config/debug/spinlock.h) \
$(wildcard include/config/lockmeter.h) \
include/linux/preempt.h \
include/linux/linkage.h \
include/asm/linkage.h \
$(wildcard include/config/regparm.h) \
$(wildcard include/config/x86/alignment/16.h) \
include/linux/thread_info.h \
include/linux/bitops.h \
include/asm/bitops.h \
include/asm/thread_info.h \
$(wildcard include/config/4kstacks.h) \
$(wildcard include/config/debug/stack/usage.h) \
include/asm/page.h \
$(wildcard include/config/x86/use/3dnow.h) \
$(wildcard include/config/x86/pae.h) \
$(wildcard include/config/hugetlb/page.h) \
$(wildcard include/config/highmem4g.h) \
$(wildcard include/config/discontigmem.h) \
include/asm/processor.h \
$(wildcard include/config/mk8.h) \
$(wildcard include/config/mk7.h) \
include/asm/vm86.h \
include/asm/math_emu.h \
include/asm/sigcontext.h \
include/asm/segment.h \
include/asm/cpufeature.h \
include/asm/msr.h \
include/asm/system.h \
$(wildcard include/config/x86/cmpxchg.h) \
$(wildcard include/config/x86/oostore.h) \
include/linux/kernel.h \
$(wildcard include/config/debug/spinlock/sleep.h) \
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
include/asm/byteorder.h \
$(wildcard include/config/x86/bswap.h) \
include/linux/byteorder/little_endian.h \
include/linux/byteorder/swab.h \
include/linux/byteorder/generic.h \
include/asm/bug.h \
include/asm-generic/bug.h \
include/linux/cache.h \
include/asm/cache.h \
$(wildcard include/config/x86/l1/cache/shift.h) \
include/linux/threads.h \
$(wildcard include/config/nr/cpus.h) \
include/asm/percpu.h \
include/asm-generic/percpu.h \
include/linux/stringify.h \
include/linux/timex.h \
$(wildcard include/config/time/interpolation.h) \
include/linux/time.h \
include/linux/seqlock.h \
include/asm/timex.h \
$(wildcard include/config/x86/elan.h) \
$(wildcard include/config/x86/tsc.h) \
$(wildcard include/config/x86/generic.h) \
include/linux/jiffies.h \
include/asm/div64.h \
include/linux/rbtree.h \
include/linux/cpumask.h \
$(wildcard include/config/hotplug/cpu.h) \
include/linux/bitmap.h \
include/linux/string.h \
include/asm/string.h \
include/asm/semaphore.h \
include/asm/atomic.h \
$(wildcard include/config/m386.h) \
include/linux/wait.h \
include/linux/list.h \
include/linux/prefetch.h \
include/asm/current.h \
include/linux/rwsem.h \
$(wildcard include/config/rwsem/generic/spinlock.h) \
include/asm/rwsem.h \
include/asm/ptrace.h \
$(wildcard include/config/frame/pointer.h) \
include/asm/mmu.h \
include/linux/smp.h \
include/linux/sem.h \
$(wildcard include/config/sysvipc.h) \
include/linux/ipc.h \
include/asm/ipcbuf.h \
include/asm/sembuf.h \
include/linux/signal.h \
include/asm/signal.h \
include/asm/siginfo.h \
include/asm-generic/siginfo.h \
include/linux/resource.h \
include/asm/resource.h \
include/linux/securebits.h \
include/linux/fs_struct.h \
include/linux/completion.h \
include/linux/pid.h \
include/linux/percpu.h \
include/linux/slab.h \
$(wildcard include/config/.h) \
include/linux/gfp.h \
include/linux/mmzone.h \
$(wildcard include/config/force/max/zoneorder.h) \
include/linux/numa.h \
include/linux/topology.h \
$(wildcard include/config/sched/smt.h) \
include/asm/topology.h \
include/asm-generic/topology.h \
include/linux/init.h \
$(wildcard include/config/hotplug.h) \
include/linux/kmalloc_sizes.h \
$(wildcard include/config/mmu.h) \
$(wildcard include/config/large/allocs.h) \
include/linux/param.h \
include/linux/timer.h \
include/linux/aio.h \
include/linux/workqueue.h \
include/linux/aio_abi.h \
include/linux/stat.h \
include/asm/stat.h \
include/linux/kmod.h \
$(wildcard include/config/kmod.h) \
include/linux/errno.h \
include/asm/errno.h \
include/asm-generic/errno.h \
include/asm-generic/errno-base.h \
include/linux/elf.h \
include/asm/elf.h \
include/asm/user.h \
include/linux/utsname.h \
include/linux/kobject.h \
include/linux/sysfs.h \
$(wildcard include/config/sysfs.h) \
include/linux/kref.h \
include/linux/kobject_uevent.h \
$(wildcard include/config/kobject/uevent.h) \
include/linux/moduleparam.h \
include/asm/local.h \
include/asm/module.h \
$(wildcard include/config/m486.h) \
$(wildcard include/config/m586.h) \
$(wildcard include/config/m586tsc.h) \
$(wildcard include/config/m586mmx.h) \
$(wildcard include/config/m686.h) \
$(wildcard include/config/mpentiumii.h) \
$(wildcard include/config/mpentiumiii.h) \
$(wildcard include/config/mpentiumm.h) \
$(wildcard include/config/mpentium4.h) \
$(wildcard include/config/mk6.h) \
$(wildcard include/config/mcrusoe.h) \
$(wildcard include/config/mefficeon.h) \
$(wildcard include/config/mwinchipc6.h) \
$(wildcard include/config/mwinchip2.h) \
$(wildcard include/config/mwinchip3d.h) \
$(wildcard include/config/mcyrixiii.h) \
$(wildcard include/config/mviac3/2.h) \
include/linux/tty.h \
$(wildcard include/config/legacy/pty/count.h) \
include/linux/fs.h \
$(wildcard include/config/dnotify.h) \
$(wildcard include/config/quota.h) \
$(wildcard include/config/epoll.h) \
$(wildcard include/config/auditsyscall.h) \
include/linux/limits.h \
include/linux/kdev_t.h \
include/linux/ioctl.h \
include/asm/ioctl.h \
include/linux/dcache.h \
include/linux/rcupdate.h \
include/linux/prio_tree.h \
include/linux/radix-tree.h \
include/linux/audit.h \
$(wildcard include/config/audit.h) \
include/linux/quota.h \
include/linux/dqblk_xfs.h \
include/linux/dqblk_v1.h \
include/linux/dqblk_v2.h \
include/linux/nfs_fs_i.h \
include/linux/nfs.h \
include/linux/sunrpc/msg_prot.h \
include/linux/fcntl.h \
include/asm/fcntl.h \
include/linux/err.h \
include/linux/major.h \
include/linux/termios.h \
include/asm/termios.h \
include/asm/termbits.h \
include/asm/ioctls.h \
include/linux/tty_driver.h \
include/linux/cdev.h \
include/linux/tty_ldisc.h \
include/linux/console.h \
include/linux/serial_core.h \
$(wildcard include/config/hard/pps.h) \
include/linux/interrupt.h \
$(wildcard include/config/generic/hardirqs.h) \
$(wildcard include/config/generic/irq/probe.h) \
include/linux/hardirq.h \
include/linux/smp_lock.h \
$(wildcard include/config/lock/kernel.h) \
include/asm/hardirq.h \
include/linux/irq.h \
$(wildcard include/config/arch/s390.h) \
include/asm/irq.h \
$(wildcard include/config/x86/local/apic.h) \
$(wildcard include/config/irqbalance.h) \
include/asm-i386/mach-default/irq_vectors.h \
include/asm-i386/mach-default/irq_vectors_limits.h \
$(wildcard include/config/pci/msi.h) \
$(wildcard include/config/x86/io/apic.h) \
include/asm/hw_irq.h \
include/linux/profile.h \
$(wildcard include/config/profiling.h) \
include/asm/sections.h \
include/asm-generic/sections.h \
include/linux/irq_cpustat.h \
include/linux/circ_buf.h \
include/linux/device.h \
include/linux/ioport.h \
include/linux/pm.h \
$(wildcard include/config/pm.h) \
include/linux/serial.h \
include/linux/delay.h \
include/asm/delay.h \
include/asm/uaccess.h \
$(wildcard include/config/x86/intel/usercopy.h) \
$(wildcard include/config/x86/wp/works/ok.h) \
drivers/serial/serial_core.o: $(deps_drivers/serial/serial_core.o)
$(deps_drivers/serial/serial_core.o):

View File

@@ -0,0 +1,544 @@
/*
* linux/drivers/char/21285.c
*
* Driver for the serial port on the 21285 StrongArm-110 core logic chip.
*
* Based on drivers/char/serial.c
*
* $Id: 21285.c,v 1.37 2002/07/28 10:03:27 rmk Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/device.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/hardware/dec21285.h>
#include <asm/hardware.h>
#define BAUD_BASE (mem_fclk_21285/64)
#define SERIAL_21285_NAME "ttyFB"
#define SERIAL_21285_MAJOR 204
#define SERIAL_21285_MINOR 4
#define RXSTAT_DUMMY_READ 0x80000000
#define RXSTAT_FRAME (1 << 0)
#define RXSTAT_PARITY (1 << 1)
#define RXSTAT_OVERRUN (1 << 2)
#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
#define H_UBRLCR_BREAK (1 << 0)
#define H_UBRLCR_PARENB (1 << 1)
#define H_UBRLCR_PAREVN (1 << 2)
#define H_UBRLCR_STOPB (1 << 3)
#define H_UBRLCR_FIFO (1 << 4)
static const char serial21285_name[] = "Footbridge UART";
#define tx_enabled(port) ((port)->unused[0])
#define rx_enabled(port) ((port)->unused[1])
/*
* The documented expression for selecting the divisor is:
* BAUD_BASE / baud - 1
* However, typically BAUD_BASE is not divisible by baud, so
* we want to select the divisor that gives us the minimum
* error. Therefore, we want:
* int(BAUD_BASE / baud - 0.5) ->
* int(BAUD_BASE / baud - (baud >> 1) / baud) ->
* int((BAUD_BASE - (baud >> 1)) / baud)
*/
static void
serial21285_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
if (tx_enabled(port)) {
disable_irq(IRQ_CONTX);
tx_enabled(port) = 0;
}
}
static void
serial21285_start_tx(struct uart_port *port, unsigned int tty_start)
{
if (!tx_enabled(port)) {
enable_irq(IRQ_CONTX);
tx_enabled(port) = 1;
}
}
static void serial21285_stop_rx(struct uart_port *port)
{
if (rx_enabled(port)) {
disable_irq(IRQ_CONRX);
rx_enabled(port) = 0;
}
}
static void serial21285_enable_ms(struct uart_port *port)
{
}
static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, flag, rxs, max_count = 256;
status = *CSR_UARTFLG;
while (!(status & 0x10) && max_count--) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
if (tty->low_latency)
tty_flip_buffer_push(tty);
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts
*/
}
ch = *CSR_UARTDR;
flag = TTY_NORMAL;
port->icount.rx++;
rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
if (rxs & RXSTAT_ANYERR) {
if (rxs & RXSTAT_PARITY)
port->icount.parity++;
else if (rxs & RXSTAT_FRAME)
port->icount.frame++;
if (rxs & RXSTAT_OVERRUN)
port->icount.overrun++;
rxs &= port->read_status_mask;
if (rxs & RXSTAT_PARITY)
flag = TTY_PARITY;
else if (rxs & RXSTAT_FRAME)
flag = TTY_FRAME;
}
if ((rxs & port->ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag);
}
if ((rxs & RXSTAT_OVERRUN) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
status = *CSR_UARTFLG;
}
tty_flip_buffer_push(tty);
out:
return IRQ_HANDLED;
}
static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
struct circ_buf *xmit = &port->info->xmit;
int count = 256;
if (port->x_char) {
*CSR_UARTDR = port->x_char;
port->icount.tx++;
port->x_char = 0;
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
serial21285_stop_tx(port, 0);
goto out;
}
do {
*CSR_UARTDR = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0 && !(*CSR_UARTFLG & 0x20));
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
serial21285_stop_tx(port, 0);
out:
return IRQ_HANDLED;
}
static unsigned int serial21285_tx_empty(struct uart_port *port)
{
return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
}
/* no modem control lines */
static unsigned int serial21285_get_mctrl(struct uart_port *port)
{
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
static void serial21285_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int h_lcr;
spin_lock_irqsave(&port->lock, flags);
h_lcr = *CSR_H_UBRLCR;
if (break_state)
h_lcr |= H_UBRLCR_BREAK;
else
h_lcr &= ~H_UBRLCR_BREAK;
*CSR_H_UBRLCR = h_lcr;
spin_unlock_irqrestore(&port->lock, flags);
}
static int serial21285_startup(struct uart_port *port)
{
int ret;
tx_enabled(port) = 1;
rx_enabled(port) = 1;
ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
serial21285_name, port);
if (ret == 0) {
ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
serial21285_name, port);
if (ret)
free_irq(IRQ_CONRX, port);
}
return ret;
}
static void serial21285_shutdown(struct uart_port *port)
{
free_irq(IRQ_CONTX, port);
free_irq(IRQ_CONRX, port);
}
static void
serial21285_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned long flags;
unsigned int baud, quot, h_lcr;
/*
* We don't support modem control lines.
*/
termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
termios->c_cflag |= CLOCAL;
/*
* We don't support BREAK character recognition.
*/
termios->c_iflag &= ~(IGNBRK | BRKINT);
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
h_lcr = 0x00;
break;
case CS6:
h_lcr = 0x20;
break;
case CS7:
h_lcr = 0x40;
break;
default: /* CS8 */
h_lcr = 0x60;
break;
}
if (termios->c_cflag & CSTOPB)
h_lcr |= H_UBRLCR_STOPB;
if (termios->c_cflag & PARENB) {
h_lcr |= H_UBRLCR_PARENB;
if (!(termios->c_cflag & PARODD))
h_lcr |= H_UBRLCR_PAREVN;
}
if (port->fifosize)
h_lcr |= H_UBRLCR_FIFO;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
/*
* Which character status flags are we interested in?
*/
port->read_status_mask = RXSTAT_OVERRUN;
if (termios->c_iflag & INPCK)
port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
/*
* Which character status flags should we ignore?
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RXSTAT_OVERRUN;
/*
* Ignore all characters if CREAD is not set.
*/
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
quot -= 1;
*CSR_UARTCON = 0;
*CSR_L_UBRLCR = quot & 0xff;
*CSR_M_UBRLCR = (quot >> 8) & 0x0f;
*CSR_H_UBRLCR = h_lcr;
*CSR_UARTCON = 1;
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *serial21285_type(struct uart_port *port)
{
return port->type == PORT_21285 ? "DC21285" : NULL;
}
static void serial21285_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, 32);
}
static int serial21285_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, 32, serial21285_name)
!= NULL ? 0 : -EBUSY;
}
static void serial21285_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
port->type = PORT_21285;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
ret = -EINVAL;
if (ser->irq != NO_IRQ)
ret = -EINVAL;
if (ser->baud_base != port->uartclk / 16)
ret = -EINVAL;
return ret;
}
static struct uart_ops serial21285_ops = {
.tx_empty = serial21285_tx_empty,
.get_mctrl = serial21285_get_mctrl,
.set_mctrl = serial21285_set_mctrl,
.stop_tx = serial21285_stop_tx,
.start_tx = serial21285_start_tx,
.stop_rx = serial21285_stop_rx,
.enable_ms = serial21285_enable_ms,
.break_ctl = serial21285_break_ctl,
.startup = serial21285_startup,
.shutdown = serial21285_shutdown,
.set_termios = serial21285_set_termios,
.type = serial21285_type,
.release_port = serial21285_release_port,
.request_port = serial21285_request_port,
.config_port = serial21285_config_port,
.verify_port = serial21285_verify_port,
};
static struct uart_port serial21285_port = {
.membase = 0,
.mapbase = 0x42000160,
.iotype = SERIAL_IO_MEM,
.irq = NO_IRQ,
.uartclk = 0,
.fifosize = 16,
.ops = &serial21285_ops,
.flags = ASYNC_BOOT_AUTOCONF,
};
static void serial21285_setup_ports(void)
{
serial21285_port.uartclk = mem_fclk_21285 / 4;
}
#ifdef CONFIG_SERIAL_21285_CONSOLE
static void
serial21285_console_write(struct console *co, const char *s,
unsigned int count)
{
int i;
for (i = 0; i < count; i++) {
while (*CSR_UARTFLG & 0x20)
barrier();
*CSR_UARTDR = s[i];
if (s[i] == '\n') {
while (*CSR_UARTFLG & 0x20)
barrier();
*CSR_UARTDR = '\r';
}
}
}
static void __init
serial21285_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
if (*CSR_UARTCON == 1) {
unsigned int tmp;
tmp = *CSR_H_UBRLCR;
switch (tmp & 0x60) {
case 0x00:
*bits = 5;
break;
case 0x20:
*bits = 6;
break;
case 0x40:
*bits = 7;
break;
default:
case 0x60:
*bits = 8;
break;
}
if (tmp & H_UBRLCR_PARENB) {
*parity = 'o';
if (tmp & H_UBRLCR_PAREVN)
*parity = 'e';
}
tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
*baud = port->uartclk / (16 * (tmp + 1));
}
}
static int __init serial21285_console_setup(struct console *co, char *options)
{
struct uart_port *port = &serial21285_port;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (machine_is_personal_server())
baud = 57600;
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
serial21285_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
extern struct uart_driver serial21285_reg;
static struct console serial21285_console =
{
.name = SERIAL_21285_NAME,
.write = serial21285_console_write,
.device = uart_console_device,
.setup = serial21285_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial21285_reg,
};
static int __init rs285_console_init(void)
{
serial21285_setup_ports();
register_console(&serial21285_console);
return 0;
}
console_initcall(rs285_console_init);
#define SERIAL_21285_CONSOLE &serial21285_console
#else
#define SERIAL_21285_CONSOLE NULL
#endif
static struct uart_driver serial21285_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyFB",
.dev_name = "ttyFB",
.devfs_name = "ttyFB",
.major = SERIAL_21285_MAJOR,
.minor = SERIAL_21285_MINOR,
.nr = 1,
.cons = SERIAL_21285_CONSOLE,
};
static int __init serial21285_init(void)
{
int ret;
printk(KERN_INFO "Serial: 21285 driver $Revision: 1.37 $\n");
serial21285_setup_ports();
ret = uart_register_driver(&serial21285_reg);
if (ret == 0)
uart_add_one_port(&serial21285_reg, &serial21285_port);
return ret;
}
static void __exit serial21285_exit(void)
{
uart_remove_one_port(&serial21285_reg, &serial21285_port);
uart_unregister_driver(&serial21285_reg);
}
module_init(serial21285_init);
module_exit(serial21285_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $");
MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
/* 68328serial.h: Definitions for the mc68328 serial driver.
*
* Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
* Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
* Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
*
* VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
*/
#ifndef _MC683XX_SERIAL_H
#define _MC683XX_SERIAL_H
#include <linux/config.h>
struct serial_struct {
int type;
int line;
int port;
int irq;
int flags;
int xmit_fifo_size;
int custom_divisor;
int baud_base;
unsigned short close_delay;
char reserved_char[2];
int hub6; /* FIXME: We don't have AT&T Hub6 boards! */
unsigned short closing_wait; /* time to wait before closing */
unsigned short closing_wait2; /* no longer used... */
int reserved[4];
};
/*
* For the close wait times, 0 means wait forever for serial port to
* flush its output. 65535 means don't wait at all.
*/
#define S_CLOSING_WAIT_INF 0
#define S_CLOSING_WAIT_NONE 65535
/*
* Definitions for S_struct (and serial_struct) flags field
*/
#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
on the callout port */
#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */
#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
#define S_SPD_MASK 0x0030
#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
#define S_SPD_CUST 0x0030 /* Use user-specified divisor */
#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
#define S_FLAGS 0x0FFF /* Possible legal S flags */
#define S_USR_MASK 0x0430 /* Legal flags that non-privileged
* users can set or reset */
/* Internal flags used only by kernel/chr_drv/serial.c */
#define S_INITIALIZED 0x80000000 /* Serial port was initialized */
#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
#define S_CLOSING 0x08000000 /* Serial port is closing */
#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */
/* Software state per channel */
#ifdef __KERNEL__
/*
* I believe this is the optimal setting that reduces the number of interrupts.
* At high speeds the output might become a little "bursted" (use USTCNT_TXHE
* if that bothers you), but in most cases it will not, since we try to
* transmit characters every time rs_interrupt is called. Thus, quite often
* you'll see that a receive interrupt occures before the transmit one.
* -- Vladimir Gurevich
*/
#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
/*
* 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
* "Old data interrupt" which occures whenever the data stay in the FIFO
* longer than 30 bits time. This allows us to use FIFO without compromising
* latency. '328 does not have this feature and without the real 328-based
* board I would assume that RXRE is the safest setting.
*
* For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
* interrupts. RXFE (receive queue full) causes the system to lose data
* at least at 115200 baud
*
* If your board is busy doing other stuff, you might consider to use
* RXRE (data ready intrrupt) instead.
*
* The other option is to make these INTR masks run-time configurable, so
* that people can dynamically adapt them according to the current usage.
* -- Vladimir Gurevich
*/
/* (es) */
#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
#elif defined(CONFIG_M68328)
#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
#else
#error Please, define the Rx interrupt events for your CPU
#endif
/* (/es) */
/*
* This is our internal structure for each serial port's state.
*
* Many fields are paralleled by the structure used by the serial_struct
* structure.
*
* For definitions of the flags field, see tty.h
*/
struct m68k_serial {
char soft_carrier; /* Use soft carrier on this channel */
char break_abort; /* Is serial console in, so process brk/abrt */
char is_cons; /* Is this our console. */
/* We need to know the current clock divisor
* to read the bps rate the chip has currently
* loaded.
*/
unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
int baud;
int magic;
int baud_base;
int port;
int irq;
int flags; /* defined in tty.h */
int type; /* UART type */
struct tty_struct *tty;
int read_status_mask;
int ignore_status_mask;
int timeout;
int xmit_fifo_size;
int custom_divisor;
int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned long event;
unsigned long last_active;
int line;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
struct work_struct tqueue;
struct work_struct tqueue_hangup;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
};
#define SERIAL_MAGIC 0x5301
/*
* The size of the serial xmit buffer is 1 page, or 4096 bytes
*/
#define SERIAL_XMIT_SIZE 4096
/*
* Events are used to schedule things to happen at timer-interrupt
* time, instead of at rs interrupt time.
*/
#define RS_EVENT_WRITE_WAKEUP 0
/*
* Define the number of ports supported and their irqs.
*/
#ifndef CONFIG_68328_SERIAL_UART2
#define NR_PORTS 1
#define UART_IRQ_DEFNS {UART_IRQ_NUM}
#else
#define NR_PORTS 2
#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM}
#endif
#endif /* __KERNEL__ */
#endif /* !(_MC683XX_SERIAL_H) */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
/*
* linux/drivers/char/8250.h
*
* Driver for 8250/16550-type serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright (C) 2001 Russell King.
*
* 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.
*
* $Id: 8250.h,v 1.8 2002/07/21 21:32:30 rmk Exp $
*/
#include <linux/config.h>
int serial8250_register_port(struct uart_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
struct old_serial_port {
unsigned int uart;
unsigned int baud_base;
unsigned int port;
unsigned int irq;
unsigned int flags;
unsigned char hub6;
unsigned char io_type;
unsigned char *iomem_base;
unsigned short iomem_reg_shift;
};
/*
* This replaces serial_uart_config in include/linux/serial.h
*/
struct serial8250_config {
const char *name;
unsigned short fifo_size;
unsigned short tx_loadsz;
unsigned char fcr;
unsigned int flags;
};
#define UART_CAP_FIFO (1 << 8) /* UART has FIFO */
#define UART_CAP_EFR (1 << 9) /* UART has EFR */
#define UART_CAP_SLEEP (1 << 10) /* UART has IER sleep */
#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */
#undef SERIAL_DEBUG_PCI
#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
#define SERIAL_INLINE
#endif
#ifdef SERIAL_INLINE
#define _INLINE_ inline
#else
#define _INLINE_
#endif
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
#define SERIAL8250_SHARE_IRQS 1
#else
#define SERIAL8250_SHARE_IRQS 0
#endif
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
* Digital did something really horribly wrong with the OUT1 and OUT2
* lines on at least some ALPHA's. The failure mode is that if either
* is cleared, the machine locks up with endless interrupts.
*/
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1)
#else
#define ALPHA_KLUDGE_MCR 0
#endif

Binary file not shown.

View File

@@ -0,0 +1,142 @@
/*
* linux/drivers/serial/acorn.c
*
* Copyright (C) 1996-2003 Russell King.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/ecard.h>
#include <asm/string.h>
#include "8250.h"
#define MAX_PORTS 3
struct serial_card_type {
unsigned int num_ports;
unsigned int uartclk;
unsigned int type;
unsigned int offset[MAX_PORTS];
};
struct serial_card_info {
unsigned int num_ports;
int ports[MAX_PORTS];
};
static int __devinit
serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct serial_card_info *info;
struct serial_card_type *type = id->data;
struct uart_port port;
unsigned long bus_addr;
unsigned char __iomem *virt_addr;
unsigned int i;
info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
memset(info, 0, sizeof(struct serial_card_info));
info->num_ports = type->num_ports;
bus_addr = ecard_resource_start(ec, type->type);
virt_addr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
if (!virt_addr) {
kfree(info);
return -ENOMEM;
}
ecard_set_drvdata(ec, info);
memset(&port, 0, sizeof(struct uart_port));
port.irq = ec->irq;
port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
port.uartclk = type->uartclk;
port.iotype = UPIO_MEM;
port.regshift = 2;
port.dev = &ec->dev;
for (i = 0; i < info->num_ports; i ++) {
port.membase = virt_addr + type->offset[i];
port.mapbase = bus_addr + type->offset[i];
info->ports[i] = serial8250_register_port(&port);
}
return 0;
}
static void __devexit serial_card_remove(struct expansion_card *ec)
{
struct serial_card_info *info = ecard_get_drvdata(ec);
int i;
ecard_set_drvdata(ec, NULL);
for (i = 0; i < info->num_ports; i++)
if (info->ports[i] > 0)
serial8250_unregister_port(info->ports[i]);
kfree(info);
}
static struct serial_card_type atomwide_type = {
.num_ports = 3,
.uartclk = 7372800,
.type = ECARD_RES_IOCSLOW,
.offset = { 0x2800, 0x2400, 0x2000 },
};
static struct serial_card_type serport_type = {
.num_ports = 2,
.uartclk = 3686400,
.type = ECARD_RES_IOCSLOW,
.offset = { 0x2000, 0x2020 },
};
static const struct ecard_id serial_cids[] = {
{ MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, &atomwide_type },
{ MANU_SERPORT, PROD_SERPORT_DSPORT, &serport_type },
{ 0xffff, 0xffff }
};
static struct ecard_driver serial_card_driver = {
.probe = serial_card_probe,
.remove = __devexit_p(serial_card_remove),
.id_table = serial_cids,
.drv = {
.name = "8250_acorn",
},
};
static int __init serial_card_init(void)
{
return ecard_register_driver(&serial_card_driver);
}
static void __exit serial_card_exit(void)
{
ecard_remove_driver(&serial_card_driver);
}
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
MODULE_LICENSE("GPL");
module_init(serial_card_init);
module_exit(serial_card_exit);

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2002-2003 Matthew Wilcox for Hewlett-Packard
* Copyright (C) 2004 Hewlett-Packard Co
* Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* 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/acpi.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/serial_core.h>
#include <acpi/acpi_bus.h>
#include <asm/io.h>
#include "8250.h"
struct serial_private {
int line;
};
static acpi_status acpi_serial_mmio(struct uart_port *port,
struct acpi_resource_address64 *addr)
{
port->mapbase = addr->min_address_range;
port->iotype = UPIO_MEM;
port->flags |= UPF_IOREMAP;
return AE_OK;
}
static acpi_status acpi_serial_port(struct uart_port *port,
struct acpi_resource_io *io)
{
if (io->range_length) {
port->iobase = io->min_base_address;
port->iotype = UPIO_PORT;
} else
printk(KERN_ERR "%s: zero-length IO port range?\n", __FUNCTION__);
return AE_OK;
}
static acpi_status acpi_serial_ext_irq(struct uart_port *port,
struct acpi_resource_ext_irq *ext_irq)
{
if (ext_irq->number_of_interrupts > 0)
port->irq = acpi_register_gsi(ext_irq->interrupts[0],
ext_irq->edge_level, ext_irq->active_high_low);
return AE_OK;
}
static acpi_status acpi_serial_irq(struct uart_port *port,
struct acpi_resource_irq *irq)
{
if (irq->number_of_interrupts > 0)
port->irq = acpi_register_gsi(irq->interrupts[0],
irq->edge_level, irq->active_high_low);
return AE_OK;
}
static acpi_status acpi_serial_resource(struct acpi_resource *res, void *data)
{
struct uart_port *port = (struct uart_port *) data;
struct acpi_resource_address64 addr;
acpi_status status;
status = acpi_resource_to_address64(res, &addr);
if (ACPI_SUCCESS(status))
return acpi_serial_mmio(port, &addr);
else if (res->id == ACPI_RSTYPE_IO)
return acpi_serial_port(port, &res->data.io);
else if (res->id == ACPI_RSTYPE_EXT_IRQ)
return acpi_serial_ext_irq(port, &res->data.extended_irq);
else if (res->id == ACPI_RSTYPE_IRQ)
return acpi_serial_irq(port, &res->data.irq);
return AE_OK;
}
static int acpi_serial_add(struct acpi_device *device)
{
struct serial_private *priv;
acpi_status status;
struct uart_port port;
int result;
memset(&port, 0, sizeof(struct uart_port));
port.uartclk = 1843200;
port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
priv = kmalloc(sizeof(struct serial_private), GFP_KERNEL);
if (!priv) {
result = -ENOMEM;
goto fail;
}
memset(priv, 0, sizeof(*priv));
status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
acpi_serial_resource, &port);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto fail;
}
if (!port.mapbase && !port.iobase) {
printk(KERN_ERR "%s: no iomem or port address in %s _CRS\n",
__FUNCTION__, device->pnp.bus_id);
result = -ENODEV;
goto fail;
}
priv->line = serial8250_register_port(&port);
if (priv->line < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n",
device->pnp.bus_id, priv->line);
result = -ENODEV;
goto fail;
}
acpi_driver_data(device) = priv;
return 0;
fail:
kfree(priv);
return result;
}
static int acpi_serial_remove(struct acpi_device *device, int type)
{
struct serial_private *priv;
if (!device || !acpi_driver_data(device))
return -EINVAL;
priv = acpi_driver_data(device);
serial8250_unregister_port(priv->line);
kfree(priv);
return 0;
}
static struct acpi_driver acpi_serial_driver = {
.name = "serial",
.class = "",
.ids = "PNP0501",
.ops = {
.add = acpi_serial_add,
.remove = acpi_serial_remove,
},
};
static int __init acpi_serial_init(void)
{
return acpi_bus_register_driver(&acpi_serial_driver);
}
static void __exit acpi_serial_exit(void)
{
acpi_bus_unregister_driver(&acpi_serial_driver);
}
module_init(acpi_serial_init);
module_exit(acpi_serial_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 ACPI serial driver");

View File

@@ -0,0 +1,255 @@
/*
* Early serial console for 8250/16550 devices
*
* (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
* and on early_printk.c by Andi Kleen.
*
* This is for use before the serial driver has initialized, in
* particular, before the UARTs have been discovered and named.
* Instead of specifying the console device as, e.g., "ttyS0",
* we locate the device directly by its MMIO or I/O port address.
*
* The user can specify the device directly, e.g.,
* console=uart,io,0x3f8,9600n8
* console=uart,mmio,0xff5e0000,115200n8
* or platform code can call early_uart_console_init() to set
* the early UART device.
*
* After the normal serial driver starts, we try to locate the
* matching ttyS device and start a console there.
*/
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/serial.h>
struct early_uart_device {
struct uart_port port;
char options[16]; /* e.g., 115200n8 */
unsigned int baud;
};
static struct early_uart_device early_device __initdata;
static int early_uart_registered __initdata;
static unsigned int __init serial_in(struct uart_port *port, int offset)
{
if (port->iotype == UPIO_MEM)
return readb(port->membase + offset);
else
return inb(port->iobase + offset);
}
static void __init serial_out(struct uart_port *port, int offset, int value)
{
if (port->iotype == UPIO_MEM)
writeb(value, port->membase + offset);
else
outb(value, port->iobase + offset);
}
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static void __init wait_for_xmitr(struct uart_port *port)
{
unsigned int status;
for (;;) {
status = serial_in(port, UART_LSR);
if ((status & BOTH_EMPTY) == BOTH_EMPTY)
return;
cpu_relax();
}
}
static void __init putc(struct uart_port *port, unsigned char c)
{
wait_for_xmitr(port);
serial_out(port, UART_TX, c);
}
static void __init early_uart_write(struct console *console, const char *s, unsigned int count)
{
struct uart_port *port = &early_device.port;
unsigned int ier;
/* Save the IER and disable interrupts */
ier = serial_in(port, UART_IER);
serial_out(port, UART_IER, 0);
while (*s && count-- > 0) {
putc(port, *s);
if (*s == '\n')
putc(port, '\r');
s++;
}
/* Wait for transmitter to become empty and restore the IER */
wait_for_xmitr(port);
serial_out(port, UART_IER, ier);
}
static unsigned int __init probe_baud(struct uart_port *port)
{
unsigned char lcr, dll, dlm;
unsigned int quot;
lcr = serial_in(port, UART_LCR);
serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
dll = serial_in(port, UART_DLL);
dlm = serial_in(port, UART_DLM);
serial_out(port, UART_LCR, lcr);
quot = (dlm << 8) | dll;
return (port->uartclk / 16) / quot;
}
static void __init init_port(struct early_uart_device *device)
{
struct uart_port *port = &device->port;
unsigned int divisor;
unsigned char c;
serial_out(port, UART_LCR, 0x3); /* 8n1 */
serial_out(port, UART_IER, 0); /* no interrupt */
serial_out(port, UART_FCR, 0); /* no fifo */
serial_out(port, UART_MCR, 0x3); /* DTR + RTS */
divisor = port->uartclk / (16 * device->baud);
c = serial_in(port, UART_LCR);
serial_out(port, UART_LCR, c | UART_LCR_DLAB);
serial_out(port, UART_DLL, divisor & 0xff);
serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
static int __init parse_options(struct early_uart_device *device, char *options)
{
struct uart_port *port = &device->port;
int mapsize = 64;
int mmio, length;
if (!options)
return -ENODEV;
port->uartclk = BASE_BAUD * 16;
if (!strncmp(options, "mmio,", 5)) {
port->iotype = UPIO_MEM;
port->mapbase = simple_strtoul(options + 5, &options, 0);
port->membase = ioremap(port->mapbase, mapsize);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
__FUNCTION__, port->mapbase);
return -ENOMEM;
}
mmio = 1;
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
port->iobase = simple_strtoul(options + 3, &options, 0);
mmio = 0;
} else
return -EINVAL;
if ((options = strchr(options, ','))) {
options++;
device->baud = simple_strtoul(options, 0, 0);
length = min(strcspn(options, " "), sizeof(device->options));
strncpy(device->options, options, length);
} else {
device->baud = probe_baud(port);
snprintf(device->options, sizeof(device->options), "%u",
device->baud);
}
printk(KERN_INFO "Early serial console at %s 0x%lx (options '%s')\n",
mmio ? "MMIO" : "I/O port",
mmio ? port->mapbase : (unsigned long) port->iobase,
device->options);
return 0;
}
static int __init early_uart_setup(struct console *console, char *options)
{
struct early_uart_device *device = &early_device;
int err;
if (device->port.membase || device->port.iobase)
return 0;
if ((err = parse_options(device, options)) < 0)
return err;
init_port(device);
return 0;
}
static struct console early_uart_console __initdata = {
.name = "uart",
.write = early_uart_write,
.setup = early_uart_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
static int __init early_uart_console_init(void)
{
if (!early_uart_registered) {
register_console(&early_uart_console);
early_uart_registered = 1;
}
return 0;
}
console_initcall(early_uart_console_init);
int __init early_serial_console_init(char *cmdline)
{
char *options;
int err;
options = strstr(cmdline, "console=uart,");
if (!options)
return -ENODEV;
options = strchr(cmdline, ',') + 1;
if ((err = early_uart_setup(NULL, options)) < 0)
return err;
return early_uart_console_init();
}
static int __init early_uart_console_switch(void)
{
struct early_uart_device *device = &early_device;
struct uart_port *port = &device->port;
int mmio, line;
if (!(early_uart_console.flags & CON_ENABLED))
return 0;
/* Try to start the normal driver on a matching line. */
mmio = (port->iotype == UPIO_MEM);
line = serial8250_start_console(port, device->options);
if (line < 0)
printk("No ttyS device at %s 0x%lx for console\n",
mmio ? "MMIO" : "I/O port",
mmio ? port->mapbase :
(unsigned long) port->iobase);
unregister_console(&early_uart_console);
if (mmio)
iounmap(port->membase);
return 0;
}
late_initcall(early_uart_console_switch);

View File

@@ -0,0 +1,120 @@
/*
* Serial Device Initialisation for Lasi/Asp/Wax/Dino
*
* (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
*
* 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/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/serial_core.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <asm/hardware.h>
#include <asm/parisc-device.h>
#include <asm/io.h>
#include <asm/serial.h> /* for LASI_BASE_BAUD */
#include "8250.h"
static int __init
serial_init_chip(struct parisc_device *dev)
{
static int serial_line_nr;
struct uart_port port;
unsigned long address;
int err;
if (!dev->irq) {
/* We find some unattached serial ports by walking native
* busses. These should be silently ignored. Otherwise,
* what we have here is a missing parent device, so tell
* the user what they're missing.
*/
if (dev->parent->id.hw_type != HPHW_IOA) {
printk(KERN_INFO "Serial: device 0x%lx not configured.\n"
"Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa);
}
return -ENODEV;
}
address = dev->hpa;
if (dev->id.sversion != 0x8d) {
address += 0x800;
}
memset(&port, 0, sizeof(struct uart_port));
port.mapbase = address;
port.irq = dev->irq;
port.iotype = UPIO_MEM;
port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
port.uartclk = LASI_BASE_BAUD * 16;
port.dev = &dev->dev;
err = serial8250_register_port(&port);
if (err < 0) {
printk(KERN_WARNING "serial8250_register_port returned error %d\n", err);
return err;
}
return 0;
}
static struct parisc_device_id serial_tbl[] = {
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 },
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c },
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d },
{ 0 }
};
/* Hack. Some machines have SERIAL_0 attached to Lasi and SERIAL_1
* attached to Dino. Unfortunately, Dino appears before Lasi in the device
* tree. To ensure that ttyS0 == SERIAL_0, we register two drivers; one
* which only knows about Lasi and then a second which will find all the
* other serial ports. HPUX ignores this problem.
*/
static struct parisc_device_id lasi_tbl[] = {
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */
{ HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */
{ 0 }
};
MODULE_DEVICE_TABLE(parisc, serial_tbl);
static struct parisc_driver lasi_driver = {
.name = "Lasi RS232",
.id_table = lasi_tbl,
.probe = serial_init_chip,
};
static struct parisc_driver serial_driver = {
.name = "Serial RS232",
.id_table = serial_tbl,
.probe = serial_init_chip,
};
int __init probe_serial_gsc(void)
{
register_parisc_driver(&lasi_driver);
register_parisc_driver(&serial_driver);
return 0;
}
module_init(probe_serial_gsc);

View File

@@ -0,0 +1,329 @@
/*
* Driver for the 98626/98644/internal serial interface on hp300/hp400
* (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
*
* Ported from 2.2 and modified to use the normal 8250 driver
* by Kars de Jong <jongk@linux-m68k.org>, May 2004.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/serial_core.h>
#include <linux/delay.h>
#include <linux/dio.h>
#include <linux/console.h>
#include <asm/io.h>
#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
#endif
#ifdef CONFIG_HPAPCI
struct hp300_port
{
struct hp300_port *next; /* next port */
int line; /* line (tty) number */
};
static struct hp300_port *hp300_ports;
#endif
#ifdef CONFIG_HPDCA
static int __devinit hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent);
static void __devexit hpdca_remove_one(struct dio_dev *d);
static struct dio_device_id hpdca_dio_tbl[] = {
{ DIO_ID_DCA0 },
{ DIO_ID_DCA0REM },
{ DIO_ID_DCA1 },
{ DIO_ID_DCA1REM },
{ 0 }
};
static struct dio_driver hpdca_driver = {
.name = "hpdca",
.id_table = hpdca_dio_tbl,
.probe = hpdca_init_one,
.remove = __devexit_p(hpdca_remove_one),
};
#endif
extern int hp300_uart_scode;
/* Offset to UART registers from base of DCA */
#define UART_OFFSET 17
#define DCA_ID 0x01 /* ID (read), reset (write) */
#define DCA_IC 0x03 /* Interrupt control */
/* Interrupt control */
#define DCA_IC_IE 0x80 /* Master interrupt enable */
#define HPDCA_BAUD_BASE 153600
/* Base address of the Frodo part */
#define FRODO_BASE (0x41c000)
/*
* Where we find the 8250-like APCI ports, and how far apart they are.
*/
#define FRODO_APCIBASE 0x0
#define FRODO_APCISPACE 0x20
#define FRODO_APCI_OFFSET(x) (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
#define HPAPCI_BAUD_BASE 500400
#ifdef CONFIG_SERIAL_8250_CONSOLE
/*
* Parse the bootinfo to find descriptions for headless console and
* debug serial ports and register them with the 8250 driver.
* This function should be called before serial_console_init() is called
* to make sure the serial console will be available for use. IA-64 kernel
* calls this function from setup_arch() after the EFI and ACPI tables have
* been parsed.
*/
int __init hp300_setup_serial_console(void)
{
int scode;
struct uart_port port;
memset(&port, 0, sizeof(port));
if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
return 0;
if (DIO_SCINHOLE(hp300_uart_scode))
return 0;
scode = hp300_uart_scode;
/* Memory mapped I/O */
port.iotype = UPIO_MEM;
port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
port.type = PORT_UNKNOWN;
/* Check for APCI console */
if (scode == 256) {
#ifdef CONFIG_HPAPCI
printk(KERN_INFO "Serial console is HP APCI 1\n");
port.uartclk = HPAPCI_BAUD_BASE * 16;
port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
port.regshift = 2;
add_preferred_console("ttyS", port.line, "9600n8");
#else
printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
return 0;
#endif
}
else {
#ifdef CONFIG_HPDCA
unsigned long pa = dio_scodetophysaddr(scode);
if (!pa) {
return 0;
}
printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
port.uartclk = HPDCA_BAUD_BASE * 16;
port.mapbase = (pa + UART_OFFSET);
port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
port.regshift = 1;
port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
/* Enable board-interrupts */
out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) {
add_preferred_console("ttyS", port.line, "9600n8");
}
#else
printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
return 0;
#endif
}
if (early_serial_setup(&port) < 0) {
printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
}
return 0;
}
#endif /* CONFIG_SERIAL_8250_CONSOLE */
#ifdef CONFIG_HPDCA
static int __devinit hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent)
{
struct serial_struct serial_req;
int line;
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (hp300_uart_scode == d->scode) {
/* Already got it. */
return 0;
}
#endif
memset(&serial_req, 0, sizeof(struct serial_struct));
/* Memory mapped I/O */
serial_req.io_type = SERIAL_IO_MEM;
serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
serial_req.irq = d->ipl;
serial_req.baud_base = HPDCA_BAUD_BASE;
serial_req.iomap_base = (d->resource.start + UART_OFFSET);
serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
serial_req.iomem_reg_shift = 1;
line = register_serial(&serial_req);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
" irq %d failed\n", d->scode, serial_req.irq);
return -ENOMEM;
}
/* Enable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
dio_set_drvdata(d, (void *)line);
/* Reset the DCA */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
udelay(100);
return 0;
}
#endif
static int __init hp300_8250_init(void)
{
static int called = 0;
int num_ports;
#ifdef CONFIG_HPAPCI
int line;
unsigned long base;
struct serial_struct serial_req;
struct hp300_port *port;
int i;
#endif
if (called)
return -ENODEV;
called = 1;
if (!MACH_IS_HP300)
return -ENODEV;
num_ports = 0;
#ifdef CONFIG_HPDCA
if (dio_module_init(&hpdca_driver) == 0)
num_ports++;
#endif
#ifdef CONFIG_HPAPCI
if (hp300_model < HP_400) {
if (!num_ports)
return -ENODEV;
return 0;
}
/* These models have the Frodo chip.
* Port 0 is reserved for the Apollo Domain keyboard.
* Port 1 is either the console or the DCA.
*/
for (i = 1; i < 4; i++) {
/* Port 1 is the console on a 425e, on other machines it's mapped to
* DCA.
*/
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (i == 1) {
continue;
}
#endif
/* Create new serial device */
port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
if (!port)
return -ENOMEM;
memset(&serial_req, 0, sizeof(struct serial_struct));
base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
/* Memory mapped I/O */
serial_req.io_type = SERIAL_IO_MEM;
serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
serial_req.irq = 0;
serial_req.baud_base = HPAPCI_BAUD_BASE;
serial_req.iomap_base = base;
serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
serial_req.iomem_reg_shift = 2;
line = register_serial(&serial_req);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
" irq %d failed\n", i, serial_req.irq);
kfree(port);
continue;
}
port->line = line;
port->next = hp300_ports;
hp300_ports = port;
num_ports++;
}
#endif
/* Any boards found? */
if (!num_ports)
return -ENODEV;
return 0;
}
#ifdef CONFIG_HPDCA
static void __devexit hpdca_remove_one(struct dio_dev *d)
{
int line;
line = (int) dio_get_drvdata(d);
if (d->resource.start) {
/* Disable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
}
unregister_serial(line);
}
#endif
static void __exit hp300_8250_exit(void)
{
#ifdef CONFIG_HPAPCI
struct hp300_port *port, *to_free;
for (port = hp300_ports; port; ) {
unregister_serial(port->line);
to_free = port;
port = port->next;
kfree(to_free);
}
hp300_ports = NULL;
#endif
#ifdef CONFIG_HPDCA
dio_unregister_driver(&hpdca_driver);
#endif
}
module_init(hp300_8250_init);
module_exit(hp300_8250_exit);
MODULE_DESCRIPTION("HP DCA/APCI serial driver");
MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,455 @@
/*
* linux/drivers/char/8250_pnp.c
*
* Probe module for 8250/16550-type ISAPNP serial ports.
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright (C) 2001 Russell King, All Rights Reserved.
*
* Ported to the Linux PnP Layer - (C) Adam Belay.
*
* 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.
*
* $Id: 8250_pnp.c,v 1.10 2002/07/21 21:32:30 rmk Exp $
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pnp.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/serial_core.h>
#include <linux/bitops.h>
#include <asm/byteorder.h>
#include "8250.h"
#define UNKNOWN_DEV 0x3000
static const struct pnp_device_id pnp_dev_table[] = {
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "AAC000F", 0 },
/* Anchor Datacomm BV */
/* SXPro 144 External Data Fax Modem Plug & Play */
{ "ADC0001", 0 },
/* SXPro 288 External Data Fax Modem Plug & Play */
{ "ADC0002", 0 },
/* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
{ "AEI0250", 0 },
/* Actiontec ISA PNP 56K X2 Fax Modem */
{ "AEI1240", 0 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ },
/* AZT3005 PnP SOUND DEVICE */
{ "AZT4001", 0 },
/* Best Data Products Inc. Smart One 336F PnP Modem */
{ "BDP3336", 0 },
/* Boca Research */
/* Boca Complete Ofc Communicator 14.4 Data-FAX */
{ "BRI0A49", 0 },
/* Boca Research 33,600 ACF Modem */
{ "BRI1400", 0 },
/* Boca 33.6 Kbps Internal FD34FSVD */
{ "BRI3400", 0 },
/* Boca 33.6 Kbps Internal FD34FSVD */
{ "BRI0A49", 0 },
/* Best Data Products Inc. Smart One 336F PnP Modem */
{ "BDP3336", 0 },
/* Computer Peripherals Inc */
/* EuroViVa CommCenter-33.6 SP PnP */
{ "CPI4050", 0 },
/* Creative Labs */
/* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
{ "CTL3001", 0 },
/* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
{ "CTL3011", 0 },
/* Creative */
/* Creative Modem Blaster Flash56 DI5601-1 */
{ "DMB1032", 0 },
/* Creative Modem Blaster V.90 DI5660 */
{ "DMB2001", 0 },
/* E-Tech */
/* E-Tech CyberBULLET PC56RVP */
{ "ETT0002", 0 },
/* FUJITSU */
/* Fujitsu 33600 PnP-I2 R Plug & Play */
{ "FUJ0202", 0 },
/* Fujitsu FMV-FX431 Plug & Play */
{ "FUJ0205", 0 },
/* Fujitsu 33600 PnP-I4 R Plug & Play */
{ "FUJ0206", 0 },
/* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
{ "FUJ0209", 0 },
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "GVC000F", 0 },
/* Hayes */
/* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
{ "HAY0001", 0 },
/* Hayes Optima 336 V.34 + FAX + Voice PnP */
{ "HAY000C", 0 },
/* Hayes Optima 336B V.34 + FAX + Voice PnP */
{ "HAY000D", 0 },
/* Hayes Accura 56K Ext Fax Modem PnP */
{ "HAY5670", 0 },
/* Hayes Accura 56K Ext Fax Modem PnP */
{ "HAY5674", 0 },
/* Hayes Accura 56K Fax Modem PnP */
{ "HAY5675", 0 },
/* Hayes 288, V.34 + FAX */
{ "HAYF000", 0 },
/* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
{ "HAYF001", 0 },
/* IBM */
/* IBM Thinkpad 701 Internal Modem Voice */
{ "IBM0033", 0 },
/* Intertex */
/* Intertex 28k8 33k6 Voice EXT PnP */
{ "IXDC801", 0 },
/* Intertex 33k6 56k Voice EXT PnP */
{ "IXDC901", 0 },
/* Intertex 28k8 33k6 Voice SP EXT PnP */
{ "IXDD801", 0 },
/* Intertex 33k6 56k Voice SP EXT PnP */
{ "IXDD901", 0 },
/* Intertex 28k8 33k6 Voice SP INT PnP */
{ "IXDF401", 0 },
/* Intertex 28k8 33k6 Voice SP EXT PnP */
{ "IXDF801", 0 },
/* Intertex 33k6 56k Voice SP EXT PnP */
{ "IXDF901", 0 },
/* Kortex International */
/* KORTEX 28800 Externe PnP */
{ "KOR4522", 0 },
/* KXPro 33.6 Vocal ASVD PnP */
{ "KORF661", 0 },
/* Lasat */
/* LASAT Internet 33600 PnP */
{ "LAS4040", 0 },
/* Lasat Safire 560 PnP */
{ "LAS4540", 0 },
/* Lasat Safire 336 PnP */
{ "LAS5440", 0 },
/* Microcom, Inc. */
/* Microcom TravelPorte FAST V.34 Plug & Play */
{ "MNP0281", 0 },
/* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
{ "MNP0336", 0 },
/* Microcom DeskPorte FAST EP 28.8 Plug & Play */
{ "MNP0339", 0 },
/* Microcom DeskPorte 28.8P Plug & Play */
{ "MNP0342", 0 },
/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{ "MNP0500", 0 },
/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{ "MNP0501", 0 },
/* Microcom DeskPorte 28.8S Internal Plug & Play */
{ "MNP0502", 0 },
/* Motorola */
/* Motorola BitSURFR Plug & Play */
{ "MOT1105", 0 },
/* Motorola TA210 Plug & Play */
{ "MOT1111", 0 },
/* Motorola HMTA 200 (ISDN) Plug & Play */
{ "MOT1114", 0 },
/* Motorola BitSURFR Plug & Play */
{ "MOT1115", 0 },
/* Motorola Lifestyle 28.8 Internal */
{ "MOT1190", 0 },
/* Motorola V.3400 Plug & Play */
{ "MOT1501", 0 },
/* Motorola Lifestyle 28.8 V.34 Plug & Play */
{ "MOT1502", 0 },
/* Motorola Power 28.8 V.34 Plug & Play */
{ "MOT1505", 0 },
/* Motorola ModemSURFR External 28.8 Plug & Play */
{ "MOT1509", 0 },
/* Motorola Premier 33.6 Desktop Plug & Play */
{ "MOT150A", 0 },
/* Motorola VoiceSURFR 56K External PnP */
{ "MOT150F", 0 },
/* Motorola ModemSURFR 56K External PnP */
{ "MOT1510", 0 },
/* Motorola ModemSURFR 56K Internal PnP */
{ "MOT1550", 0 },
/* Motorola ModemSURFR Internal 28.8 Plug & Play */
{ "MOT1560", 0 },
/* Motorola Premier 33.6 Internal Plug & Play */
{ "MOT1580", 0 },
/* Motorola OnlineSURFR 28.8 Internal Plug & Play */
{ "MOT15B0", 0 },
/* Motorola VoiceSURFR 56K Internal PnP */
{ "MOT15F0", 0 },
/* Com 1 */
/* Deskline K56 Phone System PnP */
{ "MVX00A1", 0 },
/* PC Rider K56 Phone System PnP */
{ "MVX00F2", 0 },
/* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
{ "nEC8241", 0 },
/* Pace 56 Voice Internal Plug & Play Modem */
{ "PMC2430", 0 },
/* Generic */
/* Generic standard PC COM port */
{ "PNP0500", 0 },
/* Generic 16550A-compatible COM port */
{ "PNP0501", 0 },
/* Compaq 14400 Modem */
{ "PNPC000", 0 },
/* Compaq 2400/9600 Modem */
{ "PNPC001", 0 },
/* Dial-Up Networking Serial Cable between 2 PCs */
{ "PNPC031", 0 },
/* Dial-Up Networking Parallel Cable between 2 PCs */
{ "PNPC032", 0 },
/* Standard 9600 bps Modem */
{ "PNPC100", 0 },
/* Standard 14400 bps Modem */
{ "PNPC101", 0 },
/* Standard 28800 bps Modem*/
{ "PNPC102", 0 },
/* Standard Modem*/
{ "PNPC103", 0 },
/* Standard 9600 bps Modem*/
{ "PNPC104", 0 },
/* Standard 14400 bps Modem*/
{ "PNPC105", 0 },
/* Standard 28800 bps Modem*/
{ "PNPC106", 0 },
/* Standard Modem */
{ "PNPC107", 0 },
/* Standard 9600 bps Modem */
{ "PNPC108", 0 },
/* Standard 14400 bps Modem */
{ "PNPC109", 0 },
/* Standard 28800 bps Modem */
{ "PNPC10A", 0 },
/* Standard Modem */
{ "PNPC10B", 0 },
/* Standard 9600 bps Modem */
{ "PNPC10C", 0 },
/* Standard 14400 bps Modem */
{ "PNPC10D", 0 },
/* Standard 28800 bps Modem */
{ "PNPC10E", 0 },
/* Standard Modem */
{ "PNPC10F", 0 },
/* Standard PCMCIA Card Modem */
{ "PNP2000", 0 },
/* Rockwell */
/* Modular Technology */
/* Rockwell 33.6 DPF Internal PnP */
/* Modular Technology 33.6 Internal PnP */
{ "ROK0030", 0 },
/* Kortex International */
/* KORTEX 14400 Externe PnP */
{ "ROK0100", 0 },
/* Viking Components, Inc */
/* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
{ "ROK4920", 0 },
/* Rockwell */
/* British Telecom */
/* Modular Technology */
/* Rockwell 33.6 DPF External PnP */
/* BT Prologue 33.6 External PnP */
/* Modular Technology 33.6 External PnP */
{ "RSS00A0", 0 },
/* Viking 56K FAX INT */
{ "RSS0262", 0 },
/* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
{ "RSS0250", 0 },
/* SupraExpress 28.8 Data/Fax PnP modem */
{ "SUP1310", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1421", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1590", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1760", 0 },
/* Phoebe Micro */
/* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
{ "TEX0011", 0 },
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "UAC000F", 0 },
/* 3Com Corp. */
/* Gateway Telepath IIvi 33.6 */
{ "USR0000", 0 },
/* U.S. Robotics Sporster 33.6K Fax INT PnP */
{ "USR0002", 0 },
/* Sportster Vi 14.4 PnP FAX Voicemail */
{ "USR0004", 0 },
/* U.S. Robotics 33.6K Voice INT PnP */
{ "USR0006", 0 },
/* U.S. Robotics 33.6K Voice EXT PnP */
{ "USR0007", 0 },
/* U.S. Robotics Courier V.Everything INT PnP */
{ "USR0009", 0 },
/* U.S. Robotics 33.6K Voice INT PnP */
{ "USR2002", 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR2070", 0 },
/* U.S. Robotics 56K Voice EXT PnP */
{ "USR2080", 0 },
/* U.S. Robotics 56K FAX INT */
{ "USR3031", 0 },
/* U.S. Robotics 56K FAX INT */
{ "USR3050", 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR3070", 0 },
/* U.S. Robotics 56K Voice EXT PnP */
{ "USR3080", 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR3090", 0 },
/* U.S. Robotics 56K Message */
{ "USR9100", 0 },
/* U.S. Robotics 56K FAX EXT PnP*/
{ "USR9160", 0 },
/* U.S. Robotics 56K FAX INT PnP*/
{ "USR9170", 0 },
/* U.S. Robotics 56K Voice EXT PnP*/
{ "USR9180", 0 },
/* U.S. Robotics 56K Voice INT PnP*/
{ "USR9190", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
/* Unkown PnP modems */
{ "PNPCXXX", UNKNOWN_DEV },
/* More unkown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
{ "", 0 }
};
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
static char *modem_names[] __devinitdata = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
};
static int __devinit check_name(char *name)
{
char **tmp;
for (tmp = modem_names; *tmp; tmp++)
if (strstr(name, *tmp))
return 1;
return 0;
}
static int __devinit check_resources(struct pnp_option *option)
{
struct pnp_option *tmp;
if (!option)
return 0;
for (tmp = option; tmp; tmp = tmp->next) {
struct pnp_port *port;
for (port = tmp->port; port; port = port->next)
if ((port->size == 8) &&
((port->min == 0x2f8) ||
(port->min == 0x3f8) ||
(port->min == 0x2e8) ||
(port->min == 0x3e8)))
return 1;
}
return 0;
}
/*
* Given a complete unknown PnP device, try to use some heuristics to
* detect modems. Currently use such heuristic set:
* - dev->name or dev->bus->name must contain "modem" substring;
* - device must have only one IO region (8 byte long) with base address
* 0x2e8, 0x3e8, 0x2f8 or 0x3f8.
*
* Such detection looks very ugly, but can detect at least some of numerous
* PnP modems, alternatively we must hardcode all modems in pnp_devices[]
* table.
*/
static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
{
if (!(check_name(pnp_dev_name(dev)) || (dev->card && check_name(dev->card->name))))
return -ENODEV;
if (check_resources(dev->independent))
return 0;
if (check_resources(dev->dependent))
return 0;
return -ENODEV;
}
static int __devinit
serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
{
struct uart_port port;
int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev, &flags);
if (ret < 0)
return ret;
}
memset(&port, 0, sizeof(struct uart_port));
port.irq = pnp_irq(dev,0);
port.iobase = pnp_port_start(dev, 0);
#ifdef SERIAL_DEBUG_PNP
printk("Setup PNP port: port %x, irq %d, type %d\n",
port.iobase, port.irq, port.iotype);
#endif
port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
port.uartclk = 1843200;
port.dev = &dev->dev;
line = serial8250_register_port(&port);
if (line >= 0)
pnp_set_drvdata(dev, (void *)(line + 1));
return line >= 0 ? 0 : -ENODEV;
}
static void __devexit serial_pnp_remove(struct pnp_dev * dev)
{
int line = (int)pnp_get_drvdata(dev);
if (line)
serial8250_unregister_port(line - 1);
}
static struct pnp_driver serial_pnp_driver = {
.name = "serial",
.id_table = pnp_dev_table,
.probe = serial_pnp_probe,
.remove = __devexit_p(serial_pnp_remove),
};
static int __init serial8250_pnp_init(void)
{
return pnp_register_driver(&serial_pnp_driver);
}
static void __exit serial8250_pnp_exit(void)
{
pnp_unregister_driver(&serial_pnp_driver);
}
module_init(serial8250_pnp_init);
module_exit(serial8250_pnp_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");

Binary file not shown.

View File

@@ -0,0 +1,782 @@
#
# Serial device configuration
#
# $Id: Kconfig,v 1.11 2004/03/11 18:08:04 lethal Exp $
#
menu "Serial drivers"
#
# The new 8250/16550 serial drivers
config SERIAL_8250
tristate "8250/16550 and compatible serial support"
depends on (BROKEN || !(SPARC64 || SPARC32))
select SERIAL_CORE
---help---
This selects whether you want to include the driver for the standard
serial ports. The standard answer is Y. People who might say N
here are those that are setting up dedicated Ethernet WWW/FTP
servers, or users that have one of the various bus mice instead of a
serial mouse and don't intend to use their machine's standard serial
port for anything. (Note that the Cyclades and Stallion multi
serial port drivers do not need this driver built in for them to
work.)
To compile this driver as a module, choose M here: the
module will be called serial.
[WARNING: Do not compile this driver as a module if you are using
non-standard serial ports, since the configuration information will
be lost when the driver is unloaded. This limitation may be lifted
in the future.]
BTW1: If you have a mouseman serial mouse which is not recognized by
the X window system, try running gpm first.
BTW2: If you intend to use a software modem (also called Winmodem)
under Linux, forget it. These modems are crippled and require
proprietary drivers which are only available under Windows.
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
select SERIAL_CORE_CONSOLE
---help---
If you say Y here, it will be possible to use a serial port as the
system console (the system console is the device which receives all
kernel messages and warnings and which allows logins in single user
mode). This could be useful if some terminal or printer is connected
to that serial port.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyS1". (Try "man bootparam" or see the documentation of
your boot loader (grub or lilo or loadlin) about how to pass options
to the kernel at boot time.)
If you don't have a VGA card installed and you say Y here, the
kernel will automatically use the first serial line, /dev/ttyS0, as
system console.
If unsure, say N.
config SERIAL_8250_CS
tristate "8250/16550 PCMCIA device support"
depends on PCMCIA && SERIAL_8250
---help---
Say Y here to enable support for 16-bit PCMCIA serial devices,
including serial port cards, modems, and the modem functions of
multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are
credit-card size devices often used with laptops.)
To compile this driver as a module, choose M here: the
module will be called serial_cs.
If unsure, say N.
config SERIAL_8250_ACPI
bool "8250/16550 device discovery via ACPI namespace"
default y if IA64
depends on ACPI_BUS && SERIAL_8250
---help---
If you wish to enable serial port discovery via the ACPI
namespace, say Y here. If unsure, say N.
config SERIAL_8250_NR_UARTS
int "Maximum number of non-legacy 8250/16550 serial ports"
depends on SERIAL_8250
default "4"
---help---
Set this to the number of non-legacy serial ports you want
the driver to support. This includes any ports discovered
via ACPI or PCI enumeration and any ports that may be added
at run-time via hot-plug.
config SERIAL_8250_EXTENDED
bool "Extended 8250/16550 serial driver options"
depends on SERIAL_8250
help
If you wish to use any non-standard features of the standard "dumb"
driver, say Y here. This includes HUB6 support, shared serial
interrupts, special multiport support, support for more than the
four COM 1/2/3/4 boards, etc.
Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about serial driver options. If unsure, say N.
config SERIAL_8250_MANY_PORTS
bool "Support more than 4 legacy serial ports"
depends on SERIAL_8250_EXTENDED && !IA64
help
Say Y here if you have dumb serial boards other than the four
standard COM 1/2/3/4 ports. This may happen if you have an AST
FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
from <http://www.tldp.org/docs.html#howto>), or other custom
serial port hardware which acts similar to standard serial port
hardware. If you only use the standard COM 1/2/3/4 ports, you can
say N here to save some memory. You can also say Y if you have an
"intelligent" multiport card such as Cyclades, Digiboards, etc.
config SERIAL_8250_SHARE_IRQ
bool "Support for sharing serial interrupts"
depends on SERIAL_8250_EXTENDED
help
Some serial boards have hardware support which allows multiple dumb
serial ports on the same board to share a single IRQ. To enable
support for this in the serial driver, say Y here.
config SERIAL_8250_DETECT_IRQ
bool "Autodetect IRQ on standard ports (unsafe)"
depends on SERIAL_8250_EXTENDED
help
Say Y here if you want the kernel to try to guess which IRQ
to use for your serial port.
This is considered unsafe; it is far better to configure the IRQ in
a boot script using the setserial command.
If unsure, say N.
config SERIAL_8250_MULTIPORT
bool "Support special multiport boards"
depends on SERIAL_8250_EXTENDED
help
Some multiport serial ports have special ports which are used to
signal when there are any serial ports on the board which need
servicing. Say Y here to enable the serial driver to take advantage
of those special I/O ports.
config SERIAL_8250_RSA
bool "Support RSA serial ports"
depends on SERIAL_8250_EXTENDED
help
::: To be written :::
comment "Non-8250 serial port support"
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
depends on ARM && ARCH_ACORN && SERIAL_8250
help
If you have an Atomwide Serial card or Serial Port card for an Acorn
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
config SERIAL_AMBA_PL010
tristate "ARM AMBA PL010 serial port support"
depends on ARM_AMBA
select SERIAL_CORE
help
This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have
an Integrator/AP or Integrator/PP2 platform, say Y or M here.
If unsure, say N.
config SERIAL_AMBA_PL010_CONSOLE
bool "Support for console on AMBA serial port"
depends on SERIAL_AMBA_PL010=y
select SERIAL_CORE_CONSOLE
---help---
Say Y here if you wish to use an AMBA PrimeCell UART as the system
console (the system console is the device which receives all kernel
messages and warnings and which allows logins in single user mode).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyAM0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_AMBA_PL011
tristate "ARM AMBA PL011 serial port support"
depends on ARM_AMBA
select SERIAL_CORE
help
This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have
an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
here.
If unsure, say N.
config SERIAL_AMBA_PL011_CONSOLE
bool "Support for console on AMBA serial port"
depends on SERIAL_AMBA_PL011=y
select SERIAL_CORE_CONSOLE
---help---
Say Y here if you wish to use an AMBA PrimeCell UART as the system
console (the system console is the device which receives all kernel
messages and warnings and which allows logins in single user mode).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyAM0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_CLPS711X
tristate "CLPS711X serial port support"
depends on ARM && ARCH_CLPS711X
select SERIAL_CORE
help
::: To be written :::
config SERIAL_CLPS711X_CONSOLE
bool "Support for console on CLPS711X serial port"
depends on SERIAL_CLPS711X=y
select SERIAL_CORE_CONSOLE
help
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyCL1". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_S3C2410
tristate "Samsung S3C2410 Serial port support"
depends on ARM && ARCH_S3C2410
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C2410X CPU,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured.
config SERIAL_S3C2410_CONSOLE
bool "Support for console on S3C2410 serial port"
depends on SERIAL_S3C2410=y
select SERIAL_CORE_CONSOLE
help
Allow selection of the S3C2410 on-board serial ports for use as
an virtual console.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySACx". (Try "man bootparam" or see the documentation of
your boot loader about how to pass options to the kernel at
boot time.)
config SERIAL_BAST_SIO
bool "Support for BAST SuperIO serial ports"
depends on ARCH_BAST && SERIAL_8250=y
help
Support for registerin the SuperIO chip on BAST board with
the 8250/16550 uart code.
config SERIAL_DZ
bool "DECstation DZ serial driver"
depends on MACH_DECSTATION && MIPS32
select SERIAL_CORE
help
DZ11-family serial controllers for VAXstations, including the
DC7085, M7814, and M7819.
config SERIAL_DZ_CONSOLE
bool "Support console on DECstation DZ serial driver"
depends on SERIAL_DZ=y
select SERIAL_CORE_CONSOLE
help
If you say Y here, it will be possible to use a serial port as the
system console (the system console is the device which receives all
kernel messages and warnings and which allows logins in single user
mode). Note that the firmware uses ttyS0 as the serial console on
the Maxine and ttyS2 on the others.
If unsure, say Y.
config SERIAL_21285
tristate "DC21285 serial port support"
depends on ARM && FOOTBRIDGE
select SERIAL_CORE
help
If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
PCI bridge you can enable its onboard serial port by enabling this
option.
config SERIAL_21285_CONSOLE
bool "Console on DC21285 serial port"
depends on SERIAL_21285=y
select SERIAL_CORE_CONSOLE
help
If you have enabled the serial port on the 21285 footbridge you can
make it the console by answering Y to this option.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyFB". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_UART00
bool "Excalibur serial port (uart00) support"
depends on ARM && ARCH_CAMELOT
select SERIAL_CORE
help
Say Y here if you want to use the hard logic uart on Excalibur. This
driver also supports soft logic implentations of this uart core.
config SERIAL_UART00_CONSOLE
bool "Support for console on Excalibur serial port"
depends on SERIAL_UART00
select SERIAL_CORE_CONSOLE
help
Say Y here if you want to support a serial console on an Excalibur
hard logic uart or uart00 IP core.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyS1". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_PXA
bool "PXA serial port support"
depends on ARM && ARCH_PXA
select SERIAL_CORE
help
If you have a machine based on an Intel XScale PXA2xx CPU you
can enable its onboard serial ports by enabling this option.
config SERIAL_PXA_CONSOLE
bool "Console on PXA serial port"
depends on SERIAL_PXA
select SERIAL_CORE_CONSOLE
help
If you have enabled the serial port on the Intel XScale PXA
CPU you can make it the console by answering Y to this option.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_SA1100
bool "SA1100 serial port support"
depends on ARM && ARCH_SA1100
select SERIAL_CORE
help
If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
can enable its onboard serial port by enabling this option.
Please read <file:Documentation/arm/SA1100/serial_UART> for further
info.
config SERIAL_SA1100_CONSOLE
bool "Console on SA1100 serial port"
depends on SERIAL_SA1100
select SERIAL_CORE_CONSOLE
help
If you have enabled the serial port on the SA1100/SA1110 StrongARM
CPU you can make it the console by answering Y to this option.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_IMX
bool "IMX serial port support"
depends on ARM && ARCH_IMX
select SERIAL_CORE
help
If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option.
config SERIAL_IMX_CONSOLE
bool "Console on IMX serial port"
depends on SERIAL_IMX
select SERIAL_CORE_CONSOLE
help
If you have enabled the serial port on the Motorola IMX
CPU you can make it the console by answering Y to this option.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_SUNCORE
bool
depends on SPARC32 || SPARC64
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
default y
config SERIAL_SUNZILOG
tristate "Sun Zilog8530 serial support"
depends on SPARC32 || SPARC64
help
This driver supports the Zilog8530 serial ports found on many Sparc
systems. Say Y or M if you want to be able to these serial ports.
config SERIAL_SUNZILOG_CONSOLE
bool "Console on Sun Zilog8530 serial port"
depends on SERIAL_SUNZILOG=y
help
If you would like to be able to use the Zilog8530 serial port
on your Sparc system as the console, you can do so by answering
Y to this option.
config SERIAL_SUNSU
tristate "Sun SU serial support"
depends on (SPARC32 || SPARC64) && PCI
help
This driver supports the 8250 serial ports that run the keyboard and
mouse on (PCI) UltraSPARC systems. Say Y or M if you want to be able
to these serial ports.
config SERIAL_SUNSU_CONSOLE
bool "Console on Sun SU serial port"
depends on SERIAL_SUNSU=y
help
If you would like to be able to use the SU serial port
on your Sparc system as the console, you can do so by answering
Y to this option.
config SERIAL_MUX
tristate "Serial MUX support"
depends on PARISC
select SERIAL_CORE
default y
---help---
Saying Y here will enable the hardware MUX serial driver for
the Nova and K class systems. The hardware MUX is not 8250/16550
compatible therefore the /dev/ttyB0 device is shared between the
Serial MUX and the PDC software console. The following steps
need to be completed to use the Serial MUX:
1. create the device entry (mknod /dev/ttyB0 c 11 0)
2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
3. Add device ttyB0 to /etc/securetty (if you want to log on as
root on this console.)
4. Change the kernel command console parameter to: console=ttyB0
config SERIAL_MUX_CONSOLE
bool "Support for console on serial MUX"
depends on SERIAL_MUX
select SERIAL_CORE_CONSOLE
default y
config PDC_CONSOLE
bool "PDC software console support"
depends on PARISC && !SERIAL_MUX && VT
default n
help
Saying Y here will enable the software based PDC console to be
used as the system console. This is useful for machines in
which the hardware based console has not been written yet. The
following steps must be competed to use the PDC console:
1. create the device entry (mknod /dev/ttyB0 c 11 0)
2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
3. Add device ttyB0 to /etc/securetty (if you want to log on as
root on this console.)
4. Change the kernel command console parameter to: console=ttyB0
config SERIAL_SUNSAB
tristate "Sun Siemens SAB82532 serial support"
depends on (SPARC32 || SPARC64) && PCI
help
This driver supports the Siemens SAB82532 DUSCC serial ports on newer
(PCI) UltraSPARC systems. Say Y or M if you want to be able to these
serial ports.
config SERIAL_SUNSAB_CONSOLE
bool "Console on Sun Siemens SAB82532 serial port"
depends on SERIAL_SUNSAB=y
help
If you would like to be able to use the SAB82532 serial port
on your Sparc system as the console, you can do so by answering
Y to this option.
config SERIAL_IP22_ZILOG
tristate "IP22 Zilog8530 serial support"
depends on SGI_IP22
select SERIAL_CORE
help
This driver supports the Zilog8530 serial ports found on SGI IP22
systems. Say Y or M if you want to be able to these serial ports.
config SERIAL_IP22_ZILOG_CONSOLE
bool "Console on IP22 Zilog8530 serial port"
depends on SERIAL_IP22_ZILOG=y
select SERIAL_CORE_CONSOLE
help
config V850E_UART
bool "NEC V850E on-chip UART support"
depends on V850E_MA1 || V850E_ME2 || V850E_TEG || V850E2_ANNA || V850E_AS85EP1
select SERIAL_CORE
default y
config V850E_UARTB
bool
depends V850E_UART && V850E_ME2
default y
config V850E_UART_CONSOLE
bool "Use NEC V850E on-chip UART for console"
depends on V850E_UART
select SERIAL_CORE_CONSOLE
config SERIAL_SH_SCI
tristate "SH SCI(F) serial port support"
depends on SUPERH || H8300
select SERIAL_CORE
config SERIAL_SH_SCI_CONSOLE
bool "Support for console on SH SCI(F)"
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
config SERIAL_AU1X00
bool "Enable Au1x00 UART Support"
depends on MIPS && SOC_AU1X00
select SERIAL_CORE
help
If you have an Alchemy AU1X00 processor (MIPS based) and you want
to use serial ports, say Y. Otherwise, say N.
config SERIAL_AU1X00_CONSOLE
bool "Enable Au1x00 serial console"
depends on SERIAL_AU1X00
select SERIAL_CORE_CONSOLE
help
If you have an Alchemy AU1X00 processor (MIPS based) and you want
to use a console on a serial port, say Y. Otherwise, say N.
config SERIAL_CORE
tristate
config SERIAL_CORE_CONSOLE
bool
config SERIAL_68328
bool "68328 serial support"
depends on M68328 || M68EZ328 || M68VZ328
help
This driver supports the built-in serial port of the Motorola 68328
(standard, EZ and VZ varities).
config SERIAL_68328_RTS_CTS
bool "Support RTS/CTS on 68328 serial port"
depends on SERIAL_68328
config SERIAL_COLDFIRE
bool "ColdFire serial support"
depends on COLDFIRE
help
This driver supports the built-in serial ports of the Motorola ColdFire
family of CPUs.
config SERIAL_68360_SMC
bool "68360 SMC uart support"
depends on M68360
help
This driver supports the SMC serial ports of the Motorola 68360 CPU.
config SERIAL_68360_SCC
bool "68360 SCC uart support"
depends on M68360
help
This driver supports the SCC serial ports of the Motorola 68360 CPU.
config SERIAL_68360
bool
depends on SERIAL_68360_SMC || SERIAL_68360_SCC
default y
config SERIAL_PMACZILOG
tristate "PowerMac z85c30 ESCC support"
depends on PPC_OF
select SERIAL_CORE
help
This driver supports the Zilog z85C30 serial ports found on
PowerMac machines.
Say Y or M if you want to be able to these serial ports.
config SERIAL_PMACZILOG_CONSOLE
bool "Console on PowerMac z85c30 serial port"
depends on SERIAL_PMACZILOG=y
select SERIAL_CORE_CONSOLE
help
If you would like to be able to use the z85c30 serial port
on your PowerMac as the console, you can do so by answering
Y to this option.
config SERIAL_LH7A40X
tristate "Sharp LH7A40X embedded UART support"
depends on ARM && ARCH_LH7A40X
select SERIAL_CORE
help
This enables support for the three on-board UARTs of the
Sharp LH7A40X series CPUs. Choose Y or M.
config SERIAL_LH7A40X_CONSOLE
bool "Support for connsole on Sharp LH7A40X serial port"
depends on SERIAL_LH7A40X=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use one of the serial ports as the
system console--the system console is the device which
receives all kernel messages and warnings and which allows
logins in single user mode.
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the default system console, but
you can alter that using a kernel command line, for example
"console=ttyAM1".
config SERIAL_CPM
tristate "CPM SCC/SMC serial port support"
depends on CPM2 || 8xx
select SERIAL_CORE
help
This driver supports the SCC and SMC serial ports on Motorola
embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx)
config SERIAL_CPM_CONSOLE
bool "Support for console on CPM SCC/SMC serial port"
depends on SERIAL_CPM=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you wish to use a SCC or SMC CPM UART as the system
console (the system console is the device which receives all kernel
messages and warnings and which allows logins in single user mode).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyCPM0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_CPM_SCC1
bool "Support for SCC1 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC1 as a serial port
config SERIAL_CPM_SCC2
bool "Support for SCC2 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC2 as a serial port
config SERIAL_CPM_SCC3
bool "Support for SCC3 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC3 as a serial port
config SERIAL_CPM_SCC4
bool "Support for SCC4 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SCC4 as a serial port
config SERIAL_CPM_SMC1
bool "Support for SMC1 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SMC1 as a serial port
config SERIAL_CPM_SMC2
bool "Support for SMC2 serial port"
depends on SERIAL_CPM=y
help
Select the is option to use SMC2 as a serial port
config SERIAL_SGI_L1_CONSOLE
bool "SGI Altix L1 serial console support"
depends on IA64_GENERIC || IA64_SGI_SN2
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
help
If you have an SGI Altix and you would like to use the system
controller serial port as your console (you want this!),
say Y. Otherwise, say N.
config SERIAL_MPC52xx
tristate "Freescale MPC52xx family PSC serial support"
depends on PPC_MPC52xx
select SERIAL_CORE
help
This drivers support the MPC52xx PSC serial ports. If you would
like to use them, you must answer Y or M to this option. Not that
for use as console, it must be included in kernel and not as a
module.
config SERIAL_MPC52xx_CONSOLE
bool "Console on a Freescale MPC52xx family PSC serial port"
depends on SERIAL_MPC52xx=y
select SERIAL_CORE_CONSOLE
help
Select this options if you'd like to use one of the PSC serial port
of the Freescale MPC52xx family as a console.
config SERIAL_MPC52xx_CONSOLE_BAUD
int "Freescale MPC52xx family PSC serial port baud"
depends on SERIAL_MPC52xx_CONSOLE=y
default "9600"
help
Select the MPC52xx console baud rate.
This value is only used if the bootloader doesn't pass in the
console baudrate
config SERIAL_ICOM
tristate "IBM Multiport Serial Adapter"
depends on PPC_ISERIES || PPC_PSERIES
select SERIAL_CORE
help
This driver is for a family of multiport serial adapters
including 2 port RVX, 2 port internal modem, 4 port internal
modem and a split 1 port RVX and 1 port internal modem.
This driver can also be built as a module. If so, the module
will be called icom.
config SERIAL_M32R_SIO
bool "M32R SIO I/F"
depends on M32R
default y
select SERIAL_CORE
help
Say Y here if you want to use the M32R serial controller.
config SERIAL_M32R_SIO_CONSOLE
bool "use SIO console"
depends on SERIAL_M32R_SIO=y
select SERIAL_CORE_CONSOLE
help
Say Y here if you want to support a serial console.
If you use an M3T-M32700UT or an OPSPUT platform,
please say also y for SERIAL_M32R_PLDSIO.
config SERIAL_M32R_PLDSIO
bool "M32R SIO I/F on a PLD"
depends on SERIAL_M32R_SIO=y
default n
help
Say Y here if you want to use the M32R serial controller
on a PLD (Programmable Logic Device).
If you use an M3T-M32700UT or an OPSPUT platform,
please say Y.
endmenu

View File

@@ -0,0 +1,49 @@
#
# Makefile for the kernel serial device drivers.
#
# $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $
#
serial-8250-y :=
serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o
serial-8250-$(CONFIG_GSC) += 8250_gsc.o
serial-8250-$(CONFIG_PCI) += 8250_pci.o
serial-8250-$(CONFIG_PNP) += 8250_pnp.o
serial-8250-$(CONFIG_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_UART00) += uart00.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
obj-$(CONFIG_V850E_UART) += v850e_uart.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_BAST_SIO) += bast_sio.o
obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
obj-$(CONFIG_SERIAL_IMX) += imx.o
obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
obj-$(CONFIG_SERIAL_ICOM) += icom.o
obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o

View File

@@ -0,0 +1,840 @@
/*
* linux/drivers/char/amba.c
*
* Driver for AMBA serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd.
*
* 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
*
* $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $
*
* This is a generic driver for ARM AMBA-type serial ports. They
* have a lot of 16550-like features, but are not register compatible.
* Note that although they do have CTS, DCD and DSR inputs, they do
* not have an RI input, nor do they have DTR or RTS outputs. If
* required, these have to be supplied via some other means (eg, GPIO)
* and hooked into this driver.
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/amba_serial.h>
#define UART_NR 2
#define SERIAL_AMBA_MAJOR 204
#define SERIAL_AMBA_MINOR 16
#define SERIAL_AMBA_NR UART_NR
#define AMBA_ISR_PASS_LIMIT 256
/*
* Access macros for the AMBA UARTs
*/
#define UART_GET_INT_STATUS(p) readb((p)->membase + UART010_IIR)
#define UART_PUT_ICR(p, c) writel((c), (p)->membase + UART010_ICR)
#define UART_GET_FR(p) readb((p)->membase + UART01x_FR)
#define UART_GET_CHAR(p) readb((p)->membase + UART01x_DR)
#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + UART01x_DR)
#define UART_GET_RSR(p) readb((p)->membase + UART01x_RSR)
#define UART_GET_CR(p) readb((p)->membase + UART010_CR)
#define UART_PUT_CR(p,c) writel((c), (p)->membase + UART010_CR)
#define UART_GET_LCRL(p) readb((p)->membase + UART010_LCRL)
#define UART_PUT_LCRL(p,c) writel((c), (p)->membase + UART010_LCRL)
#define UART_GET_LCRM(p) readb((p)->membase + UART010_LCRM)
#define UART_PUT_LCRM(p,c) writel((c), (p)->membase + UART010_LCRM)
#define UART_GET_LCRH(p) readb((p)->membase + UART010_LCRH)
#define UART_PUT_LCRH(p,c) writel((c), (p)->membase + UART010_LCRH)
#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0)
#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0)
#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART01x_FR_TMSK) == 0)
#define UART_DUMMY_RSR_RX /*256*/0
#define UART_PORT_SIZE 64
/*
* On the Integrator platform, the port RTS and DTR are provided by
* bits in the following SC_CTRLS register bits:
* RTS DTR
* UART0 7 6
* UART1 5 4
*/
#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
/*
* We wrap our port structure around the generic uart_port.
*/
struct uart_amba_port {
struct uart_port port;
unsigned int dtr_mask;
unsigned int rts_mask;
unsigned int old_status;
};
static void pl010_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
unsigned int cr;
cr = UART_GET_CR(port);
cr &= ~UART010_CR_TIE;
UART_PUT_CR(port, cr);
}
static void pl010_start_tx(struct uart_port *port, unsigned int tty_start)
{
unsigned int cr;
cr = UART_GET_CR(port);
cr |= UART010_CR_TIE;
UART_PUT_CR(port, cr);
}
static void pl010_stop_rx(struct uart_port *port)
{
unsigned int cr;
cr = UART_GET_CR(port);
cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
UART_PUT_CR(port, cr);
}
static void pl010_enable_ms(struct uart_port *port)
{
unsigned int cr;
cr = UART_GET_CR(port);
cr |= UART010_CR_MSIE;
UART_PUT_CR(port, cr);
}
static void
#ifdef SUPPORT_SYSRQ
pl010_rx_chars(struct uart_port *port, struct pt_regs *regs)
#else
pl010_rx_chars(struct uart_port *port)
#endif
{
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, flag, rsr, max_count = 256;
status = UART_GET_FR(port);
while (UART_RX_DATA(status) && max_count--) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
if (tty->low_latency)
tty_flip_buffer_push(tty);
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts.
*/
}
ch = UART_GET_CHAR(port);
flag = TTY_NORMAL;
port->icount.rx++;
/*
* Note that the error handling code is
* out of the main execution path
*/
rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
if (rsr & UART01x_RSR_ANY) {
if (rsr & UART01x_RSR_BE) {
rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
} else if (rsr & UART01x_RSR_PE)
port->icount.parity++;
else if (rsr & UART01x_RSR_FE)
port->icount.frame++;
if (rsr & UART01x_RSR_OE)
port->icount.overrun++;
rsr &= port->read_status_mask;
if (rsr & UART01x_RSR_BE)
flag = TTY_BREAK;
else if (rsr & UART01x_RSR_PE)
flag = TTY_PARITY;
else if (rsr & UART01x_RSR_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch, regs))
goto ignore_char;
if ((rsr & port->ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag);
}
if ((rsr & UART01x_RSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char:
status = UART_GET_FR(port);
}
tty_flip_buffer_push(tty);
return;
}
static void pl010_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
int count;
if (port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
pl010_stop_tx(port, 0);
return;
}
count = port->fifosize >> 1;
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
pl010_stop_tx(port, 0);
}
static void pl010_modem_status(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status, delta;
UART_PUT_ICR(&uap->port, 0);
status = UART_GET_FR(&uap->port) & UART01x_FR_MODEM_ANY;
delta = status ^ uap->old_status;
uap->old_status = status;
if (!delta)
return;
if (delta & UART01x_FR_DCD)
uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
if (delta & UART01x_FR_DSR)
uap->port.icount.dsr++;
if (delta & UART01x_FR_CTS)
uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
wake_up_interruptible(&uap->port.info->delta_msr_wait);
}
static irqreturn_t pl010_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
spin_lock(&port->lock);
status = UART_GET_INT_STATUS(port);
if (status) {
do {
if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
#ifdef SUPPORT_SYSRQ
pl010_rx_chars(port, regs);
#else
pl010_rx_chars(port);
#endif
if (status & UART010_IIR_MIS)
pl010_modem_status(port);
if (status & UART010_IIR_TIS)
pl010_tx_chars(port);
if (pass_counter-- == 0)
break;
status = UART_GET_INT_STATUS(port);
} while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
UART010_IIR_TIS));
handled = 1;
}
spin_unlock(&port->lock);
return IRQ_RETVAL(handled);
}
static unsigned int pl010_tx_empty(struct uart_port *port)
{
return UART_GET_FR(port) & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
}
static unsigned int pl010_get_mctrl(struct uart_port *port)
{
unsigned int result = 0;
unsigned int status;
status = UART_GET_FR(port);
if (status & UART01x_FR_DCD)
result |= TIOCM_CAR;
if (status & UART01x_FR_DSR)
result |= TIOCM_DSR;
if (status & UART01x_FR_CTS)
result |= TIOCM_CTS;
return result;
}
static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int ctrls = 0, ctrlc = 0;
if (mctrl & TIOCM_RTS)
ctrlc |= uap->rts_mask;
else
ctrls |= uap->rts_mask;
if (mctrl & TIOCM_DTR)
ctrlc |= uap->dtr_mask;
else
ctrls |= uap->dtr_mask;
__raw_writel(ctrls, SC_CTRLS);
__raw_writel(ctrlc, SC_CTRLC);
}
static void pl010_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int lcr_h;
spin_lock_irqsave(&port->lock, flags);
lcr_h = UART_GET_LCRH(port);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
UART_PUT_LCRH(port, lcr_h);
spin_unlock_irqrestore(&port->lock, flags);
}
static int pl010_startup(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
int retval;
/*
* Allocate the IRQ
*/
retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", port);
if (retval)
return retval;
/*
* initialise the old status of the modem signals
*/
uap->old_status = UART_GET_FR(port) & UART01x_FR_MODEM_ANY;
/*
* Finally, enable interrupts
*/
UART_PUT_CR(port, UART01x_CR_UARTEN | UART010_CR_RIE |
UART010_CR_RTIE);
return 0;
}
static void pl010_shutdown(struct uart_port *port)
{
/*
* Free the interrupt
*/
free_irq(port->irq, port);
/*
* disable all interrupts, disable the port
*/
UART_PUT_CR(port, 0);
/* disable break condition and fifos */
UART_PUT_LCRH(port, UART_GET_LCRH(port) &
~(UART01x_LCRH_BRK | UART01x_LCRH_FEN));
}
static void
pl010_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr_h = UART01x_LCRH_WLEN_5;
break;
case CS6:
lcr_h = UART01x_LCRH_WLEN_6;
break;
case CS7:
lcr_h = UART01x_LCRH_WLEN_7;
break;
default: // CS8
lcr_h = UART01x_LCRH_WLEN_8;
break;
}
if (termios->c_cflag & CSTOPB)
lcr_h |= UART01x_LCRH_STP2;
if (termios->c_cflag & PARENB) {
lcr_h |= UART01x_LCRH_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
}
if (port->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UART01x_RSR_OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= UART01x_RSR_BE;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= UART01x_RSR_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART01x_RSR_OE;
}
/*
* Ignore all characters if CREAD is not set.
*/
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= UART_DUMMY_RSR_RX;
/* first, disable everything */
old_cr = UART_GET_CR(port) & ~UART010_CR_MSIE;
if (UART_ENABLE_MS(port, termios->c_cflag))
old_cr |= UART010_CR_MSIE;
UART_PUT_CR(port, 0);
/* Set baud rate */
quot -= 1;
UART_PUT_LCRM(port, ((quot & 0xf00) >> 8));
UART_PUT_LCRL(port, (quot & 0xff));
/*
* ----------v----------v----------v----------v-----
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
* ----------^----------^----------^----------^-----
*/
UART_PUT_LCRH(port, lcr_h);
UART_PUT_CR(port, old_cr);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *pl010_type(struct uart_port *port)
{
return port->type == PORT_AMBA ? "AMBA" : NULL;
}
/*
* Release the memory region(s) being used by 'port'
*/
static void pl010_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, UART_PORT_SIZE);
}
/*
* Request the memory region(s) being used by 'port'
*/
static int pl010_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010")
!= NULL ? 0 : -EBUSY;
}
/*
* Configure/autoconfigure the port.
*/
static void pl010_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_AMBA;
pl010_request_port(port);
}
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
static struct uart_ops amba_pl010_pops = {
.tx_empty = pl010_tx_empty,
.set_mctrl = pl010_set_mctrl,
.get_mctrl = pl010_get_mctrl,
.stop_tx = pl010_stop_tx,
.start_tx = pl010_start_tx,
.stop_rx = pl010_stop_rx,
.enable_ms = pl010_enable_ms,
.break_ctl = pl010_break_ctl,
.startup = pl010_startup,
.shutdown = pl010_shutdown,
.set_termios = pl010_set_termios,
.type = pl010_type,
.release_port = pl010_release_port,
.request_port = pl010_request_port,
.config_port = pl010_config_port,
.verify_port = pl010_verify_port,
};
static struct uart_amba_port amba_ports[UART_NR] = {
{
.port = {
.membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
.mapbase = INTEGRATOR_UART0_BASE,
.iotype = SERIAL_IO_MEM,
.irq = IRQ_UARTINT0,
.uartclk = 14745600,
.fifosize = 16,
.ops = &amba_pl010_pops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 0,
},
.dtr_mask = 1 << 5,
.rts_mask = 1 << 4,
},
{
.port = {
.membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
.mapbase = INTEGRATOR_UART1_BASE,
.iotype = SERIAL_IO_MEM,
.irq = IRQ_UARTINT1,
.uartclk = 14745600,
.fifosize = 16,
.ops = &amba_pl010_pops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 1,
},
.dtr_mask = 1 << 7,
.rts_mask = 1 << 6,
}
};
#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
static void
pl010_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_port *port = &amba_ports[co->index].port;
unsigned int status, old_cr;
int i;
/*
* First save the CR then disable the interrupts
*/
old_cr = UART_GET_CR(port);
UART_PUT_CR(port, UART01x_CR_UARTEN);
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
do {
status = UART_GET_FR(port);
} while (!UART_TX_READY(status));
UART_PUT_CHAR(port, s[i]);
if (s[i] == '\n') {
do {
status = UART_GET_FR(port);
} while (!UART_TX_READY(status));
UART_PUT_CHAR(port, '\r');
}
}
/*
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
do {
status = UART_GET_FR(port);
} while (status & UART01x_FR_BUSY);
UART_PUT_CR(port, old_cr);
}
static void __init
pl010_console_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
if (UART_GET_CR(port) & UART01x_CR_UARTEN) {
unsigned int lcr_h, quot;
lcr_h = UART_GET_LCRH(port);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
if (lcr_h & UART01x_LCRH_EPS)
*parity = 'e';
else
*parity = 'o';
}
if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
*bits = 7;
else
*bits = 8;
quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8;
*baud = port->uartclk / (16 * (quot + 1));
}
}
static int __init pl010_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index >= UART_NR)
co->index = 0;
port = &amba_ports[co->index].port;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
pl010_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
extern struct uart_driver amba_reg;
static struct console amba_console = {
.name = "ttyAM",
.write = pl010_console_write,
.device = uart_console_device,
.setup = pl010_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &amba_reg,
};
static int __init amba_console_init(void)
{
/*
* All port initializations are done statically
*/
register_console(&amba_console);
return 0;
}
console_initcall(amba_console_init);
static int __init amba_late_console_init(void)
{
if (!(amba_console.flags & CON_ENABLED))
register_console(&amba_console);
return 0;
}
late_initcall(amba_late_console_init);
#define AMBA_CONSOLE &amba_console
#else
#define AMBA_CONSOLE NULL
#endif
static struct uart_driver amba_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyAM",
.dev_name = "ttyAM",
.major = SERIAL_AMBA_MAJOR,
.minor = SERIAL_AMBA_MINOR,
.nr = UART_NR,
.cons = AMBA_CONSOLE,
};
static int pl010_probe(struct amba_device *dev, void *id)
{
int i;
for (i = 0; i < UART_NR; i++) {
if (amba_ports[i].port.mapbase != dev->res.start)
continue;
amba_ports[i].port.dev = &dev->dev;
uart_add_one_port(&amba_reg, &amba_ports[i].port);
amba_set_drvdata(dev, &amba_ports[i]);
break;
}
return 0;
}
static int pl010_remove(struct amba_device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
if (uap)
uart_remove_one_port(&amba_reg, &uap->port);
amba_set_drvdata(dev, NULL);
return 0;
}
static int pl010_suspend(struct amba_device *dev, u32 state)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
if (uap)
uart_suspend_port(&amba_reg, &uap->port);
return 0;
}
static int pl010_resume(struct amba_device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
if (uap)
uart_resume_port(&amba_reg, &uap->port);
return 0;
}
static struct amba_id pl010_ids[] __initdata = {
{
.id = 0x00041010,
.mask = 0x000fffff,
},
{ 0, 0 },
};
static struct amba_driver pl010_driver = {
.drv = {
.name = "uart-pl010",
},
.id_table = pl010_ids,
.probe = pl010_probe,
.remove = pl010_remove,
.suspend = pl010_suspend,
.resume = pl010_resume,
};
static int __init pl010_init(void)
{
int ret;
printk(KERN_INFO "Serial: AMBA driver $Revision: 1.41 $\n");
ret = uart_register_driver(&amba_reg);
if (ret == 0) {
ret = amba_driver_register(&pl010_driver);
if (ret)
uart_unregister_driver(&amba_reg);
}
return ret;
}
static void __exit pl010_exit(void)
{
amba_driver_unregister(&pl010_driver);
uart_unregister_driver(&amba_reg);
}
module_init(pl010_init);
module_exit(pl010_exit);
MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.41 $");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,869 @@
/*
* linux/drivers/char/amba.c
*
* Driver for AMBA serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd.
*
* 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
*
* $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $
*
* This is a generic driver for ARM AMBA-type serial ports. They
* have a lot of 16550-like features, but are not register compatible.
* Note that although they do have CTS, DCD and DSR inputs, they do
* not have an RI input, nor do they have DTR or RTS outputs. If
* required, these have to be supplied via some other means (eg, GPIO)
* and hooked into this driver.
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/clock.h>
#include <asm/hardware/amba_serial.h>
#define UART_NR 14
#define SERIAL_AMBA_MAJOR 204
#define SERIAL_AMBA_MINOR 64
#define SERIAL_AMBA_NR UART_NR
#define AMBA_ISR_PASS_LIMIT 256
#define UART_DUMMY_RSR_RX 256
/*
* We wrap our port structure around the generic uart_port.
*/
struct uart_amba_port {
struct uart_port port;
struct clk *clk;
unsigned int im; /* interrupt mask */
unsigned int old_status;
};
static void pl011_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
uap->im &= ~UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
}
static void pl011_start_tx(struct uart_port *port, unsigned int tty_start)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
uap->im |= UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
}
static void pl011_stop_rx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
UART011_PEIM|UART011_BEIM|UART011_OEIM);
writew(uap->im, uap->port.membase + UART011_IMSC);
}
static void pl011_enable_ms(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
}
static void
#ifdef SUPPORT_SYSRQ
pl011_rx_chars(struct uart_amba_port *uap, struct pt_regs *regs)
#else
pl011_rx_chars(struct uart_amba_port *uap)
#endif
{
struct tty_struct *tty = uap->port.info->tty;
unsigned int status, ch, flag, rsr, max_count = 256;
status = readw(uap->port.membase + UART01x_FR);
while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
if (tty->low_latency)
tty_flip_buffer_push(tty);
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts
*/
}
ch = readw(uap->port.membase + UART01x_DR);
flag = TTY_NORMAL;
uap->port.icount.rx++;
/*
* Note that the error handling code is
* out of the main execution path
*/
rsr = readw(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
if (rsr & UART01x_RSR_ANY) {
if (rsr & UART01x_RSR_BE) {
rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
uap->port.icount.brk++;
if (uart_handle_break(&uap->port))
goto ignore_char;
} else if (rsr & UART01x_RSR_PE)
uap->port.icount.parity++;
else if (rsr & UART01x_RSR_FE)
uap->port.icount.frame++;
if (rsr & UART01x_RSR_OE)
uap->port.icount.overrun++;
rsr &= uap->port.read_status_mask;
if (rsr & UART01x_RSR_BE)
flag = TTY_BREAK;
else if (rsr & UART01x_RSR_PE)
flag = TTY_PARITY;
else if (rsr & UART01x_RSR_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&uap->port, ch, regs))
goto ignore_char;
if ((rsr & uap->port.ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag);
}
if ((rsr & UART01x_RSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char:
status = readw(uap->port.membase + UART01x_FR);
}
tty_flip_buffer_push(tty);
return;
}
static void pl011_tx_chars(struct uart_amba_port *uap)
{
struct circ_buf *xmit = &uap->port.info->xmit;
int count;
if (uap->port.x_char) {
writew(uap->port.x_char, uap->port.membase + UART01x_DR);
uap->port.icount.tx++;
uap->port.x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
pl011_stop_tx(&uap->port, 0);
return;
}
count = uap->port.fifosize >> 1;
do {
writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
uap->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
if (uart_circ_empty(xmit))
pl011_stop_tx(&uap->port, 0);
}
static void pl011_modem_status(struct uart_amba_port *uap)
{
unsigned int status, delta;
status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
delta = status ^ uap->old_status;
uap->old_status = status;
if (!delta)
return;
if (delta & UART01x_FR_DCD)
uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
if (delta & UART01x_FR_DSR)
uap->port.icount.dsr++;
if (delta & UART01x_FR_CTS)
uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
wake_up_interruptible(&uap->port.info->delta_msr_wait);
}
static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_amba_port *uap = dev_id;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
spin_lock(&uap->port.lock);
status = readw(uap->port.membase + UART011_MIS);
if (status) {
do {
writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS),
uap->port.membase + UART011_ICR);
if (status & (UART011_RTIS|UART011_RXIS))
#ifdef SUPPORT_SYSRQ
pl011_rx_chars(uap, regs);
#else
pl011_rx_chars(uap);
#endif
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
if (status & UART011_TXIS)
pl011_tx_chars(uap);
if (pass_counter-- == 0)
break;
status = readw(uap->port.membase + UART011_MIS);
} while (status != 0);
handled = 1;
}
spin_unlock(&uap->port.lock);
return IRQ_RETVAL(handled);
}
static unsigned int pl01x_tx_empty(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status = readw(uap->port.membase + UART01x_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
static unsigned int pl01x_get_mctrl(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int result = 0;
unsigned int status = readw(uap->port.membase + UART01x_FR);
#define BIT(uartbit, tiocmbit) \
if (status & uartbit) \
result |= tiocmbit
BIT(UART01x_FR_DCD, TIOCM_CAR);
BIT(UART01x_FR_DSR, TIOCM_DSR);
BIT(UART01x_FR_CTS, TIOCM_CTS);
BIT(UART011_FR_RI, TIOCM_RNG);
#undef BIT
return result;
}
static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
cr = readw(uap->port.membase + UART011_CR);
#define BIT(tiocmbit, uartbit) \
if (mctrl & tiocmbit) \
cr |= uartbit; \
else \
cr &= ~uartbit
BIT(TIOCM_RTS, UART011_CR_RTS);
BIT(TIOCM_DTR, UART011_CR_DTR);
BIT(TIOCM_OUT1, UART011_CR_OUT1);
BIT(TIOCM_OUT2, UART011_CR_OUT2);
BIT(TIOCM_LOOP, UART011_CR_LBE);
#undef BIT
writew(cr, uap->port.membase + UART011_CR);
}
static void pl011_break_ctl(struct uart_port *port, int break_state)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned long flags;
unsigned int lcr_h;
spin_lock_irqsave(&uap->port.lock, flags);
lcr_h = readw(uap->port.membase + UART011_LCRH);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
writew(lcr_h, uap->port.membase + UART011_LCRH);
spin_unlock_irqrestore(&uap->port.lock, flags);
}
static int pl011_startup(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
int retval;
/*
* Try to enable the clock producer.
*/
retval = clk_enable(uap->clk);
if (retval)
goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
/*
* Allocate the IRQ
*/
retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
if (retval)
goto clk_dis;
writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
uap->port.membase + UART011_IFLS);
/*
* Provoke TX FIFO interrupt into asserting.
*/
cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
writew(cr, uap->port.membase + UART011_CR);
writew(0, uap->port.membase + UART011_FBRD);
writew(1, uap->port.membase + UART011_IBRD);
writew(0, uap->port.membase + UART011_LCRH);
writew(0, uap->port.membase + UART01x_DR);
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
barrier();
cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR);
/*
* initialise the old status of the modem signals
*/
uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
/*
* Finally, enable interrupts
*/
spin_lock_irq(&uap->port.lock);
uap->im = UART011_RXIM | UART011_RTIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);
return 0;
clk_dis:
clk_disable(uap->clk);
out:
return retval;
}
static void pl011_shutdown(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned long val;
/*
* disable all interrupts
*/
spin_lock_irq(&uap->port.lock);
uap->im = 0;
writew(uap->im, uap->port.membase + UART011_IMSC);
writew(0xffff, uap->port.membase + UART011_ICR);
spin_unlock_irq(&uap->port.lock);
/*
* Free the interrupt
*/
free_irq(uap->port.irq, uap);
/*
* disable the port
*/
writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
/*
* disable break condition and fifos
*/
val = readw(uap->port.membase + UART011_LCRH);
val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
writew(val, uap->port.membase + UART011_LCRH);
/*
* Shut down the clock producer
*/
clk_disable(uap->clk);
}
static void
pl011_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = port->uartclk * 4 / baud;
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr_h = UART01x_LCRH_WLEN_5;
break;
case CS6:
lcr_h = UART01x_LCRH_WLEN_6;
break;
case CS7:
lcr_h = UART01x_LCRH_WLEN_7;
break;
default: // CS8
lcr_h = UART01x_LCRH_WLEN_8;
break;
}
if (termios->c_cflag & CSTOPB)
lcr_h |= UART01x_LCRH_STP2;
if (termios->c_cflag & PARENB) {
lcr_h |= UART01x_LCRH_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
}
if (port->fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UART01x_RSR_OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= UART01x_RSR_BE;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= UART01x_RSR_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART01x_RSR_OE;
}
/*
* Ignore all characters if CREAD is not set.
*/
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= UART_DUMMY_RSR_RX;
if (UART_ENABLE_MS(port, termios->c_cflag))
pl011_enable_ms(port);
/* first, disable everything */
old_cr = readw(port->membase + UART011_CR);
writew(0, port->membase + UART011_CR);
/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
/*
* ----------v----------v----------v----------v-----
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
* ----------^----------^----------^----------^-----
*/
writew(lcr_h, port->membase + UART011_LCRH);
writew(old_cr, port->membase + UART011_CR);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *pl011_type(struct uart_port *port)
{
return port->type == PORT_AMBA ? "AMBA/PL011" : NULL;
}
/*
* Release the memory region(s) being used by 'port'
*/
static void pl010_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, SZ_4K);
}
/*
* Request the memory region(s) being used by 'port'
*/
static int pl010_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
!= NULL ? 0 : -EBUSY;
}
/*
* Configure/autoconfigure the port.
*/
static void pl010_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_AMBA;
pl010_request_port(port);
}
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
static struct uart_ops amba_pl011_pops = {
.tx_empty = pl01x_tx_empty,
.set_mctrl = pl011_set_mctrl,
.get_mctrl = pl01x_get_mctrl,
.stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx,
.enable_ms = pl011_enable_ms,
.break_ctl = pl011_break_ctl,
.startup = pl011_startup,
.shutdown = pl011_shutdown,
.set_termios = pl011_set_termios,
.type = pl011_type,
.release_port = pl010_release_port,
.request_port = pl010_request_port,
.config_port = pl010_config_port,
.verify_port = pl010_verify_port,
};
static struct uart_amba_port *amba_ports[UART_NR];
#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
static inline void
pl011_console_write_char(struct uart_amba_port *uap, char ch)
{
unsigned int status;
do {
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_TXFF);
writew(ch, uap->port.membase + UART01x_DR);
}
static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_amba_port *uap = amba_ports[co->index];
unsigned int status, old_cr, new_cr;
int i;
clk_enable(uap->clk);
/*
* First save the CR then disable the interrupts
*/
old_cr = readw(uap->port.membase + UART011_CR);
new_cr = old_cr & ~UART011_CR_CTSEN;
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
writew(new_cr, uap->port.membase + UART011_CR);
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
pl011_console_write_char(uap, s[i]);
if (s[i] == '\n')
pl011_console_write_char(uap, '\r');
}
/*
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
do {
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_BUSY);
writew(old_cr, uap->port.membase + UART011_CR);
clk_disable(uap->clk);
}
static void __init
pl011_console_get_options(struct uart_amba_port *uap, int *baud,
int *parity, int *bits)
{
if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, ibrd, fbrd;
lcr_h = readw(uap->port.membase + UART011_LCRH);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
if (lcr_h & UART01x_LCRH_EPS)
*parity = 'e';
else
*parity = 'o';
}
if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
*bits = 7;
else
*bits = 8;
ibrd = readw(uap->port.membase + UART011_IBRD);
fbrd = readw(uap->port.membase + UART011_FBRD);
*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
}
}
static int __init pl011_console_setup(struct console *co, char *options)
{
struct uart_amba_port *uap;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index >= UART_NR)
co->index = 0;
uap = amba_ports[co->index];
uap->port.uartclk = clk_get_rate(uap->clk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
pl011_console_get_options(uap, &baud, &parity, &bits);
return uart_set_options(&uap->port, co, baud, parity, bits, flow);
}
extern struct uart_driver amba_reg;
static struct console amba_console = {
.name = "ttyAMA",
.write = pl011_console_write,
.device = uart_console_device,
.setup = pl011_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &amba_reg,
};
#define AMBA_CONSOLE (&amba_console)
#else
#define AMBA_CONSOLE NULL
#endif
static struct uart_driver amba_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyAMA",
.dev_name = "ttyAMA",
.major = SERIAL_AMBA_MAJOR,
.minor = SERIAL_AMBA_MINOR,
.nr = UART_NR,
.cons = AMBA_CONSOLE,
};
static int pl011_probe(struct amba_device *dev, void *id)
{
struct uart_amba_port *uap;
void __iomem *base;
int i, ret;
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == NULL)
break;
if (i == ARRAY_SIZE(amba_ports)) {
ret = -EBUSY;
goto out;
}
uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
if (uap == NULL) {
ret = -ENOMEM;
goto out;
}
base = ioremap(dev->res.start, PAGE_SIZE);
if (!base) {
ret = -ENOMEM;
goto free;
}
memset(uap, 0, sizeof(struct uart_amba_port));
uap->clk = clk_get(&dev->dev, "UARTCLK");
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
goto unmap;
}
ret = clk_use(uap->clk);
if (ret)
goto putclk;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
uap->port.iotype = UPIO_MEM;
uap->port.irq = dev->irq[0];
uap->port.fifosize = 16;
uap->port.ops = &amba_pl011_pops;
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = i;
amba_ports[i] = uap;
amba_set_drvdata(dev, uap);
ret = uart_add_one_port(&amba_reg, &uap->port);
if (ret) {
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
clk_unuse(uap->clk);
putclk:
clk_put(uap->clk);
unmap:
iounmap(base);
free:
kfree(uap);
}
out:
return ret;
}
static int pl011_remove(struct amba_device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
int i;
amba_set_drvdata(dev, NULL);
uart_remove_one_port(&amba_reg, &uap->port);
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == uap)
amba_ports[i] = NULL;
iounmap(uap->port.membase);
clk_unuse(uap->clk);
clk_put(uap->clk);
kfree(uap);
return 0;
}
static struct amba_id pl011_ids[] __initdata = {
{
.id = 0x00041011,
.mask = 0x000fffff,
},
{ 0, 0 },
};
static struct amba_driver pl011_driver = {
.drv = {
.name = "uart-pl011",
},
.id_table = pl011_ids,
.probe = pl011_probe,
.remove = pl011_remove,
};
static int __init pl011_init(void)
{
int ret;
printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
ret = uart_register_driver(&amba_reg);
if (ret == 0) {
ret = amba_driver_register(&pl011_driver);
if (ret)
uart_unregister_driver(&amba_reg);
}
return ret;
}
static void __exit pl011_exit(void)
{
amba_driver_unregister(&pl011_driver);
uart_unregister_driver(&amba_reg);
}
module_init(pl011_init);
module_exit(pl011_exit);
MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
MODULE_DESCRIPTION("ARM AMBA serial port driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
/* linux/drivers/serial/bast_sio.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://www.simtec.co.uk/products/EB2410ITX/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Modifications:
* 23-Sep-2004 BJD Added copyright header
* 23-Sep-2004 BJD Added serial port remove code
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/serial.h>
#include <asm/mach-types.h>
#include <asm/arch/map.h>
#include <asm/arch/irqs.h>
#include <asm/arch/bast-map.h>
#include <asm/arch/bast-irq.h>
static int __init serial_bast_register(unsigned long port, unsigned int irq)
{
struct serial_struct serial_req;
serial_req.flags = UPF_AUTOPROBE | UPF_SHARE_IRQ;
serial_req.baud_base = BASE_BAUD;
serial_req.irq = irq;
serial_req.io_type = UPIO_MEM;
serial_req.iomap_base = port;
serial_req.iomem_base = ioremap(port, 0x10);
serial_req.iomem_reg_shift = 0;
return register_serial(&serial_req);
}
#define SERIAL_BASE (S3C2410_CS2 + BAST_PA_SUPERIO)
static int port[2] = { -1, -1 };
static int __init serial_bast_init(void)
{
if (machine_is_bast()) {
port[0] = serial_bast_register(SERIAL_BASE + 0x2f8, IRQ_PCSERIAL1);
port[1] = serial_bast_register(SERIAL_BASE + 0x3f8, IRQ_PCSERIAL2);
}
return 0;
}
static void __exit serial_bast_exit(void)
{
if (port[0] != -1)
unregister_serial(port[0]);
if (port[1] != -1)
unregister_serial(port[1]);
}
module_init(serial_bast_init);
module_exit(serial_bast_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks, ben@simtec.co.uk");
MODULE_DESCRIPTION("BAST Onboard Serial setup");

Binary file not shown.

View File

@@ -0,0 +1,609 @@
/*
* linux/drivers/char/clps711x.c
*
* Driver for CLPS711x serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd.
*
* 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
*
* $Id: clps711x.c,v 1.42 2002/07/28 10:03:28 rmk Exp $
*
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware/clps7111.h>
#define UART_NR 2
#define SERIAL_CLPS711X_MAJOR 204
#define SERIAL_CLPS711X_MINOR 40
#define SERIAL_CLPS711X_NR UART_NR
/*
* We use the relevant SYSCON register as a base address for these ports.
*/
#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1)
#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1)
#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1)
#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1)
#define TX_IRQ(port) ((port)->irq)
#define RX_IRQ(port) ((port)->irq + 1)
#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
#define tx_enabled(port) ((port)->unused[0])
static void
clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
if (tx_enabled(port)) {
disable_irq(TX_IRQ(port));
tx_enabled(port) = 0;
}
}
static void
clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start)
{
if (!tx_enabled(port)) {
enable_irq(TX_IRQ(port));
tx_enabled(port) = 1;
}
}
static void clps711xuart_stop_rx(struct uart_port *port)
{
disable_irq(RX_IRQ(port));
}
static void clps711xuart_enable_ms(struct uart_port *port)
{
}
static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, flg, ignored = 0;
status = clps_readl(SYSFLG(port));
while (!(status & SYSFLG_URXFE)) {
ch = clps_readl(UARTDR(port));
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
goto ignore_char;
port->icount.rx++;
flg = TTY_NORMAL;
/*
* Note that the error handling code is
* out of the main execution path
*/
if (ch & UART_ANY_ERR)
goto handle_error;
if (uart_handle_sysrq_char(port, ch, regs))
goto ignore_char;
error_return:
tty_insert_flip_char(tty, ch, flg);
ignore_char:
status = clps_readl(SYSFLG(port));
}
out:
tty_flip_buffer_push(tty);
return IRQ_HANDLED;
handle_error:
if (ch & UARTDR_PARERR)
port->icount.parity++;
else if (ch & UARTDR_FRMERR)
port->icount.frame++;
if (ch & UARTDR_OVERR)
port->icount.overrun++;
if (ch & port->ignore_status_mask) {
if (++ignored > 100)
goto out;
goto ignore_char;
}
ch &= port->read_status_mask;
if (ch & UARTDR_PARERR)
flg = TTY_PARITY;
else if (ch & UARTDR_FRMERR)
flg = TTY_FRAME;
if (ch & UARTDR_OVERR) {
/*
* CHECK: does overrun affect the current character?
* ASSUMPTION: it does not.
*/
tty_insert_flip_char(tty, ch, flg);
ch = 0;
flg = TTY_OVERRUN;
}
#ifdef SUPPORT_SYSRQ
port->sysrq = 0;
#endif
goto error_return;
}
static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
struct circ_buf *xmit = &port->info->xmit;
int count;
if (port->x_char) {
clps_writel(port->x_char, UARTDR(port));
port->icount.tx++;
port->x_char = 0;
return IRQ_HANDLED;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
clps711xuart_stop_tx(port, 0);
return IRQ_HANDLED;
}
count = port->fifosize >> 1;
do {
clps_writel(xmit->buf[xmit->tail], UARTDR(port));
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
clps711xuart_stop_tx(port, 0);
return IRQ_HANDLED;
}
static unsigned int clps711xuart_tx_empty(struct uart_port *port)
{
unsigned int status = clps_readl(SYSFLG(port));
return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
}
static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
{
unsigned int port_addr;
unsigned int result = 0;
unsigned int status;
port_addr = SYSFLG(port);
if (port_addr == SYSFLG1) {
status = clps_readl(SYSFLG1);
if (status & SYSFLG1_DCD)
result |= TIOCM_CAR;
if (status & SYSFLG1_DSR)
result |= TIOCM_DSR;
if (status & SYSFLG1_CTS)
result |= TIOCM_CTS;
}
return result;
}
static void
clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
{
}
static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int ubrlcr;
spin_lock_irqsave(&port->lock, flags);
ubrlcr = clps_readl(UBRLCR(port));
if (break_state == -1)
ubrlcr |= UBRLCR_BREAK;
else
ubrlcr &= ~UBRLCR_BREAK;
clps_writel(ubrlcr, UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags);
}
static int clps711xuart_startup(struct uart_port *port)
{
unsigned int syscon;
int retval;
tx_enabled(port) = 1;
/*
* Allocate the IRQs
*/
retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
"clps711xuart_tx", port);
if (retval)
return retval;
retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
"clps711xuart_rx", port);
if (retval) {
free_irq(TX_IRQ(port), port);
return retval;
}
/*
* enable the port
*/
syscon = clps_readl(SYSCON(port));
syscon |= SYSCON_UARTEN;
clps_writel(syscon, SYSCON(port));
return 0;
}
static void clps711xuart_shutdown(struct uart_port *port)
{
unsigned int ubrlcr, syscon;
/*
* Free the interrupt
*/
free_irq(TX_IRQ(port), port); /* TX interrupt */
free_irq(RX_IRQ(port), port); /* RX interrupt */
/*
* disable the port
*/
syscon = clps_readl(SYSCON(port));
syscon &= ~SYSCON_UARTEN;
clps_writel(syscon, SYSCON(port));
/*
* disable break condition and fifos
*/
ubrlcr = clps_readl(UBRLCR(port));
ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
clps_writel(ubrlcr, UBRLCR(port));
}
static void
clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int ubrlcr, baud, quot;
unsigned long flags;
/*
* We don't implement CREAD.
*/
termios->c_cflag |= CREAD;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
case CS5:
ubrlcr = UBRLCR_WRDLEN5;
break;
case CS6:
ubrlcr = UBRLCR_WRDLEN6;
break;
case CS7:
ubrlcr = UBRLCR_WRDLEN7;
break;
default: // CS8
ubrlcr = UBRLCR_WRDLEN8;
break;
}
if (termios->c_cflag & CSTOPB)
ubrlcr |= UBRLCR_XSTOP;
if (termios->c_cflag & PARENB) {
ubrlcr |= UBRLCR_PRTEN;
if (!(termios->c_cflag & PARODD))
ubrlcr |= UBRLCR_EVENPRT;
}
if (port->fifosize > 1)
ubrlcr |= UBRLCR_FIFOEN;
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UARTDR_OVERR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
if (termios->c_iflag & IGNBRK) {
/*
* If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UARTDR_OVERR;
}
quot -= 1;
clps_writel(ubrlcr | quot, UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *clps711xuart_type(struct uart_port *port)
{
return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
}
/*
* Configure/autoconfigure the port.
*/
static void clps711xuart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_CLPS711X;
}
static void clps711xuart_release_port(struct uart_port *port)
{
}
static int clps711xuart_request_port(struct uart_port *port)
{
return 0;
}
static struct uart_ops clps711x_pops = {
.tx_empty = clps711xuart_tx_empty,
.set_mctrl = clps711xuart_set_mctrl_null,
.get_mctrl = clps711xuart_get_mctrl,
.stop_tx = clps711xuart_stop_tx,
.start_tx = clps711xuart_start_tx,
.stop_rx = clps711xuart_stop_rx,
.enable_ms = clps711xuart_enable_ms,
.break_ctl = clps711xuart_break_ctl,
.startup = clps711xuart_startup,
.shutdown = clps711xuart_shutdown,
.set_termios = clps711xuart_set_termios,
.type = clps711xuart_type,
.config_port = clps711xuart_config_port,
.release_port = clps711xuart_release_port,
.request_port = clps711xuart_request_port,
};
static struct uart_port clps711x_ports[UART_NR] = {
{
.iobase = SYSCON1,
.irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
.uartclk = 3686400,
.fifosize = 16,
.ops = &clps711x_pops,
.line = 0,
.flags = ASYNC_BOOT_AUTOCONF,
},
{
.iobase = SYSCON2,
.irq = IRQ_UTXINT2, /* IRQ_URXINT2 */
.uartclk = 3686400,
.fifosize = 16,
.ops = &clps711x_pops,
.line = 1,
.flags = ASYNC_BOOT_AUTOCONF,
}
};
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* The console_lock must be held when we get here.
*
* Note that this is called with interrupts already disabled
*/
static void
clps711xuart_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_port *port = clps711x_ports + co->index;
unsigned int status, syscon;
int i;
/*
* Ensure that the port is enabled.
*/
syscon = clps_readl(SYSCON(port));
clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
do {
status = clps_readl(SYSFLG(port));
} while (status & SYSFLG_UTXFF);
clps_writel(s[i], UARTDR(port));
if (s[i] == '\n') {
do {
status = clps_readl(SYSFLG(port));
} while (status & SYSFLG_UTXFF);
clps_writel('\r', UARTDR(port));
}
}
/*
* Finally, wait for transmitter to become empty
* and restore the uart state.
*/
do {
status = clps_readl(SYSFLG(port));
} while (status & SYSFLG_UBUSY);
clps_writel(syscon, SYSCON(port));
}
static void __init
clps711xuart_console_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
unsigned int ubrlcr, quot;
ubrlcr = clps_readl(UBRLCR(port));
*parity = 'n';
if (ubrlcr & UBRLCR_PRTEN) {
if (ubrlcr & UBRLCR_EVENPRT)
*parity = 'e';
else
*parity = 'o';
}
if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
*bits = 7;
else
*bits = 8;
quot = ubrlcr & UBRLCR_BAUD_MASK;
*baud = port->uartclk / (16 * (quot + 1));
}
}
static int __init clps711xuart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
port = uart_get_console(clps711x_ports, UART_NR, co);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
clps711xuart_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
extern struct uart_driver clps711x_reg;
static struct console clps711x_console = {
.name = "ttyCL",
.write = clps711xuart_console_write,
.device = uart_console_device,
.setup = clps711xuart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &clps711x_reg,
};
static int __init clps711xuart_console_init(void)
{
register_console(&clps711x_console);
return 0;
}
console_initcall(clps711xuart_console_init);
#define CLPS711X_CONSOLE &clps711x_console
#else
#define CLPS711X_CONSOLE NULL
#endif
static struct uart_driver clps711x_reg = {
.driver_name = "ttyCL",
.dev_name = "ttyCL",
.major = SERIAL_CLPS711X_MAJOR,
.minor = SERIAL_CLPS711X_MINOR,
.nr = UART_NR,
.cons = CLPS711X_CONSOLE,
};
static int __init clps711xuart_init(void)
{
int ret, i;
printk(KERN_INFO "Serial: CLPS711x driver $Revision: 1.42 $\n");
ret = uart_register_driver(&clps711x_reg);
if (ret)
return ret;
for (i = 0; i < UART_NR; i++)
uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
return 0;
}
static void __exit clps711xuart_exit(void)
{
int i;
for (i = 0; i < UART_NR; i++)
uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
uart_unregister_driver(&clps711x_reg);
}
module_init(clps711xuart_init);
module_exit(clps711xuart_exit);
MODULE_AUTHOR("Deep Blue Solutions Ltd");
MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.42 $");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);

View File

@@ -0,0 +1,11 @@
#
# Makefile for the Motorola 8xx FEC ethernet controller
#
obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o
# Select the correct platform objects.
cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o
cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o
cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y)

View File

@@ -0,0 +1,89 @@
/*
* linux/drivers/serial/cpm_uart.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
*
*/
#ifndef CPM_UART_H
#define CPM_UART_H
#include <linux/config.h>
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
#elif defined(CONFIG_8xx)
#include "cpm_uart_cpm1.h"
#endif
#define SERIAL_CPM_MAJOR 204
#define SERIAL_CPM_MINOR 46
#define IS_SMC(pinfo) (pinfo->flags & FLAG_SMC)
#define IS_DISCARDING(pinfo) (pinfo->flags & FLAG_DISCARDING)
#define FLAG_DISCARDING 0x00000004 /* when set, don't discard */
#define FLAG_SMC 0x00000002
#define FLAG_CONSOLE 0x00000001
#define UART_SMC1 0
#define UART_SMC2 1
#define UART_SCC1 2
#define UART_SCC2 3
#define UART_SCC3 4
#define UART_SCC4 5
#define UART_NR 6
#define RX_NUM_FIFO 4
#define RX_BUF_SIZE 32
#define TX_NUM_FIFO 4
#define TX_BUF_SIZE 32
struct uart_cpm_port {
struct uart_port port;
u16 rx_nrfifos;
u16 rx_fifosize;
u16 tx_nrfifos;
u16 tx_fifosize;
smc_t *smcp;
smc_uart_t *smcup;
scc_t *sccp;
scc_uart_t *sccup;
volatile cbd_t *rx_bd_base;
volatile cbd_t *rx_cur;
volatile cbd_t *tx_bd_base;
volatile cbd_t *tx_cur;
unsigned char *tx_buf;
unsigned char *rx_buf;
u32 flags;
void (*set_lineif)(struct uart_cpm_port *);
u8 brg;
uint dp_addr;
void *mem_addr;
dma_addr_t dma_addr;
/* helpers */
int baud;
int bits;
/* Keep track of 'odd' SMC2 wirings */
int is_portb;
};
extern int cpm_uart_port_map[UART_NR];
extern int cpm_uart_nr;
extern struct uart_cpm_port cpm_uart_ports[UART_NR];
/* these are located in their respective files */
void cpm_line_cr_cmd(int line, int cmd);
int cpm_uart_init_portdesc(void);
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
void smc1_lineif(struct uart_cpm_port *pinfo);
void smc2_lineif(struct uart_cpm_port *pinfo);
void scc1_lineif(struct uart_cpm_port *pinfo);
void scc2_lineif(struct uart_cpm_port *pinfo);
void scc3_lineif(struct uart_cpm_port *pinfo);
void scc4_lineif(struct uart_cpm_port *pinfo);
#endif /* CPM_UART_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,290 @@
/*
* linux/drivers/serial/cpm_uart.c
*
* Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
*
* Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
*
* 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
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/**************************************************************/
void cpm_line_cr_cmd(int line, int cmd)
{
ushort val;
volatile cpm8xx_t *cp = cpmp;
switch (line) {
case UART_SMC1:
val = mk_cr_cmd(CPM_CR_CH_SMC1, cmd) | CPM_CR_FLG;
break;
case UART_SMC2:
val = mk_cr_cmd(CPM_CR_CH_SMC2, cmd) | CPM_CR_FLG;
break;
case UART_SCC1:
val = mk_cr_cmd(CPM_CR_CH_SCC1, cmd) | CPM_CR_FLG;
break;
case UART_SCC2:
val = mk_cr_cmd(CPM_CR_CH_SCC2, cmd) | CPM_CR_FLG;
break;
case UART_SCC3:
val = mk_cr_cmd(CPM_CR_CH_SCC3, cmd) | CPM_CR_FLG;
break;
case UART_SCC4:
val = mk_cr_cmd(CPM_CR_CH_SCC4, cmd) | CPM_CR_FLG;
break;
default:
return;
}
cp->cp_cpcr = val;
while (cp->cp_cpcr & CPM_CR_FLG) ;
}
void smc1_lineif(struct uart_cpm_port *pinfo)
{
volatile cpm8xx_t *cp = cpmp;
unsigned int iobits = 0x000000c0;
if (!pinfo->is_portb) {
cp->cp_pbpar |= iobits;
cp->cp_pbdir &= ~iobits;
cp->cp_pbodr &= ~iobits;
} else {
((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
}
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SMC2: insert port configuration here */
pinfo->brg = 2;
}
void scc1_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC1: insert port configuration here */
pinfo->brg = 1;
}
void scc2_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC2: insert port configuration here */
pinfo->brg = 2;
}
void scc3_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC3: insert port configuration here */
pinfo->brg = 3;
}
void scc4_lineif(struct uart_cpm_port *pinfo)
{
/* XXX SCC4: insert port configuration here */
pinfo->brg = 4;
}
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
* receive buffer descriptors from dual port ram, and a character
* buffer area from host mem. If we are allocating for the console we need
* to do it from bootmem
*/
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
u8 *dp_mem;
uint dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_offset = cpm_dpalloc(dpmemsz, 8);
if (IS_DPERR(dp_offset)) {
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
return -ENOMEM;
}
dp_mem = cpm_dpram_addr(dp_offset);
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
if (is_con) {
mem_addr = (u8 *) m8xx_cpm_hostalloc(memsz);
dma_addr = 0;
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
if (mem_addr == NULL) {
cpm_dpfree(dp_offset);
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate coherent memory\n");
return -ENOMEM;
}
pinfo->dp_addr = dp_offset;
pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
}
void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
{
dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
pinfo->tx_fifosize), pinfo->mem_addr,
pinfo->dma_addr);
cpm_dpfree(pinfo->dp_addr);
}
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
pr_debug("CPM uart[-]:init portdesc\n");
cpm_uart_nr = 0;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0];
/*
* Is SMC1 being relocated?
*/
# ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpmp->cp_dparam[0x3C0];
# else
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC1];
# endif
cpm_uart_ports[UART_SMC1].port.mapbase =
(unsigned long)&cpmp->cp_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
cpm_uart_ports[UART_SMC2].smcp = &cpmp->cp_smc[1];
cpm_uart_ports[UART_SMC2].smcup =
(smc_uart_t *) & cpmp->cp_dparam[PROFF_SMC2];
cpm_uart_ports[UART_SMC2].port.mapbase =
(unsigned long)&cpmp->cp_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
cpm_uart_ports[UART_SCC1].sccp = &cpmp->cp_scc[0];
cpm_uart_ports[UART_SCC1].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC1];
cpm_uart_ports[UART_SCC1].port.mapbase =
(unsigned long)&cpmp->cp_scc[0];
cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
cpm_uart_ports[UART_SCC2].sccp = &cpmp->cp_scc[1];
cpm_uart_ports[UART_SCC2].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC2];
cpm_uart_ports[UART_SCC2].port.mapbase =
(unsigned long)&cpmp->cp_scc[1];
cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
cpm_uart_ports[UART_SCC3].sccp = &cpmp->cp_scc[2];
cpm_uart_ports[UART_SCC3].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC3];
cpm_uart_ports[UART_SCC3].port.mapbase =
(unsigned long)&cpmp->cp_scc[2];
cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
cpm_uart_ports[UART_SCC4].sccp = &cpmp->cp_scc[3];
cpm_uart_ports[UART_SCC4].sccup =
(scc_uart_t *) & cpmp->cp_dparam[PROFF_SCC4];
cpm_uart_ports[UART_SCC4].port.mapbase =
(unsigned long)&cpmp->cp_scc[3];
cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
return 0;
}

View File

@@ -0,0 +1,45 @@
/*
* linux/drivers/serial/cpm_uart_cpm1.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm1
*
*/
#ifndef CPM_UART_CPM1_H
#define CPM_UART_CPM1_H
#include <asm/commproc.h>
/* defines for IRQs */
#define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1)
#define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2)
#define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1)
#define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2)
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
/* the CPM address */
#define CPM_ADDR IMAP_ADDR
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
}
static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
{
sup->scc_genscc.scc_rfcr = SMC_EB;
sup->scc_genscc.scc_tfcr = SMC_EB;
}
static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
{
up->smc_rfcr = SMC_EB;
up->smc_tfcr = SMC_EB;
}
#define DPRAM_BASE ((unsigned char *)&cpmp->cp_dpmem[0])
#endif

View File

@@ -0,0 +1,328 @@
/*
* linux/drivers/serial/cpm_uart_cpm2.c
*
* Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
*
* Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
*
* 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
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include "cpm_uart.h"
/**************************************************************/
void cpm_line_cr_cmd(int line, int cmd)
{
volatile cpm_cpm2_t *cp = cpmp;
ulong val;
switch (line) {
case UART_SMC1:
val = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SMC2:
val = mk_cr_cmd(CPM_CR_SMC2_PAGE, CPM_CR_SMC2_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC1:
val = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC2:
val = mk_cr_cmd(CPM_CR_SCC2_PAGE, CPM_CR_SCC2_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC3:
val = mk_cr_cmd(CPM_CR_SCC3_PAGE, CPM_CR_SCC3_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
case UART_SCC4:
val = mk_cr_cmd(CPM_CR_SCC4_PAGE, CPM_CR_SCC4_SBLOCK, 0,
cmd) | CPM_CR_FLG;
break;
default:
return;
}
cp->cp_cpcr = val;
while (cp->cp_cpcr & CPM_CR_FLG) ;
}
void smc1_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
/* SMC1 is only on port D */
io->iop_ppard |= 0x00c00000;
io->iop_pdird |= 0x00400000;
io->iop_pdird &= ~0x00800000;
io->iop_psord &= ~0x00c00000;
/* Wire BRG1 to SMC1 */
cpm2_immr->im_cpmux.cmx_smr &= 0x0f;
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
/* SMC2 is only on port A */
io->iop_ppara |= 0x00c00000;
io->iop_pdira |= 0x00400000;
io->iop_pdira &= ~0x00800000;
io->iop_psora &= ~0x00c00000;
/* Wire BRG2 to SMC2 */
cpm2_immr->im_cpmux.cmx_smr &= 0xf0;
pinfo->brg = 2;
}
void scc1_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
/* Use Port D for SCC1 instead of other functions. */
io->iop_ppard |= 0x00000003;
io->iop_psord &= ~0x00000001; /* Rx */
io->iop_psord |= 0x00000002; /* Tx */
io->iop_pdird &= ~0x00000001; /* Rx */
io->iop_pdird |= 0x00000002; /* Tx */
/* Wire BRG1 to SCC1 */
cpm2_immr->im_cpmux.cmx_scr &= ~0x00ffffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00000000;
pinfo->brg = 1;
}
void scc2_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
cpm2_immr->im_cpmux.cmx_scr &= ~0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
}
void scc3_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
cpm2_immr->im_cpmux.cmx_scr &= ~0xffff00ff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00001200;
pinfo->brg = 3;
}
void scc4_lineif(struct uart_cpm_port *pinfo)
{
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_ppard |= 0x00000600;
io->iop_psord &= ~0x00000600; /* Tx/Rx */
io->iop_pdird &= ~0x00000200; /* Rx */
io->iop_pdird |= 0x00000400; /* Tx */
cpm2_immr->im_cpmux.cmx_scr &= ~0xffffff00;
cpm2_immr->im_cpmux.cmx_scr |= 0x0000001b;
pinfo->brg = 4;
}
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
* receive buffer descriptors from dual port ram, and a character
* buffer area from host mem. If we are allocating for the console we need
* to do it from bootmem
*/
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
u8 *dp_mem;
uint dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
pr_debug("CPM uart[%d]:allocbuf\n", pinfo->port.line);
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_offset = cpm_dpalloc(dpmemsz, 8);
if (IS_DPERR(dp_offset)) {
printk(KERN_ERR
"cpm_uart_cpm.c: could not allocate buffer descriptors\n");
return -ENOMEM;
}
dp_mem = cpm_dpram_addr(dp_offset);
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
if (is_con)
mem_addr = alloc_bootmem(memsz);
else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
if (mem_addr == NULL) {
cpm_dpfree(dp_offset);
printk(KERN_ERR
"cpm_uart_cpm.c: could not allocate coherent memory\n");
return -ENOMEM;
}
pinfo->dp_addr = dp_offset;
pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
}
void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
{
dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
pinfo->tx_fifosize), pinfo->mem_addr,
pinfo->dma_addr);
cpm_dpfree(pinfo->dp_addr);
}
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
pr_debug("CPM uart[-]:init portdesc\n");
cpm_uart_nr = 0;
#ifdef CONFIG_SERIAL_CPM_SMC1
cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
cpm_uart_ports[UART_SMC1].smcup =
(smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
cpm_uart_ports[UART_SMC1].port.mapbase =
(unsigned long)&cpm2_immr->im_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
cpm_uart_ports[UART_SMC2].smcup =
(smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
cpm_uart_ports[UART_SMC2].port.mapbase =
(unsigned long)&cpm2_immr->im_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
cpm_uart_ports[UART_SCC1].sccp = (scc_t *) & cpm2_immr->im_scc[0];
cpm_uart_ports[UART_SCC1].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC1];
cpm_uart_ports[UART_SCC1].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[0];
cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
cpm_uart_ports[UART_SCC2].sccp = (scc_t *) & cpm2_immr->im_scc[1];
cpm_uart_ports[UART_SCC2].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC2];
cpm_uart_ports[UART_SCC2].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[1];
cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
cpm_uart_ports[UART_SCC3].sccp = (scc_t *) & cpm2_immr->im_scc[2];
cpm_uart_ports[UART_SCC3].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC3];
cpm_uart_ports[UART_SCC3].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[2];
cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
cpm_uart_ports[UART_SCC4].sccp = (scc_t *) & cpm2_immr->im_scc[3];
cpm_uart_ports[UART_SCC4].sccup =
(scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC4];
cpm_uart_ports[UART_SCC4].port.mapbase =
(unsigned long)&cpm2_immr->im_scc[3];
cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
return 0;
}

View File

@@ -0,0 +1,45 @@
/*
* linux/drivers/serial/cpm_uart_cpm2.h
*
* Driver for CPM (SCC/SMC) serial ports
*
* definitions for cpm2
*
*/
#ifndef CPM_UART_CPM2_H
#define CPM_UART_CPM2_H
#include <asm/cpm2.h>
/* defines for IRQs */
#define SMC1_IRQ SIU_INT_SMC1
#define SMC2_IRQ SIU_INT_SMC2
#define SCC1_IRQ SIU_INT_SCC1
#define SCC2_IRQ SIU_INT_SCC2
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
/* the CPM address */
#define CPM_ADDR CPM_MAP_ADDR
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
}
static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
{
sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
}
static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
{
up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
}
#define DPRAM_BASE ((unsigned char *)&cpm2_immr->im_dprambase[0])
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
/*
* serial.h: Arch-dep definitions for the Etrax100 serial driver.
*
* Copyright (C) 1998, 1999, 2000 Axis Communications AB
*/
#ifndef _ETRAX_SERIAL_H
#define _ETRAX_SERIAL_H
#include <linux/config.h>
#include <linux/circ_buf.h>
#include <asm/termios.h>
/* Software state per channel */
#ifdef __KERNEL__
/*
* This is our internal structure for each serial port's state.
*
* Many fields are paralleled by the structure used by the serial_struct
* structure.
*
* For definitions of the flags field, see tty.h
*/
#define SERIAL_RECV_DESCRIPTORS 8
struct etrax_recv_buffer {
struct etrax_recv_buffer *next;
unsigned short length;
unsigned char error;
unsigned char pad;
unsigned char buffer[0];
};
struct e100_serial {
int baud;
volatile u8 *port; /* R_SERIALx_CTRL */
u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */
/* Output registers */
volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */
volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */
const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */
/* Input registers */
volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */
volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
int flags; /* defined in tty.h */
u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
u8 iseteop; /* bit number for R_SET_EOP for the input dma */
int enabled; /* Set to 1 if the port is enabled in HW config */
u8 dma_out_enabled:1; /* Set to 1 if DMA should be used */
u8 dma_in_enabled:1; /* Set to 1 if DMA should be used */
/* end of fields defined in rs_table[] in .c-file */
u8 uses_dma_in; /* Set to 1 if DMA is used */
u8 uses_dma_out; /* Set to 1 if DMA is used */
u8 forced_eop; /* a fifo eop has been forced */
int baud_base; /* For special baudrates */
int custom_divisor; /* For special baudrates */
struct etrax_dma_descr tr_descr;
struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS];
int cur_rec_descr;
volatile int tr_running; /* 1 if output is running */
struct tty_struct *tty;
int read_status_mask;
int ignore_status_mask;
int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned long event;
unsigned long last_active;
int line;
int type; /* PORT_ETRAX */
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
struct circ_buf xmit;
struct etrax_recv_buffer *first_recv_buffer;
struct etrax_recv_buffer *last_recv_buffer;
unsigned int recv_cnt;
unsigned int max_recv_cnt;
struct work_struct work;
struct async_icount icount; /* error-statistics etc.*/
struct termios normal_termios;
struct termios callout_termios;
#ifdef DECLARE_WAITQUEUE
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
#else
struct wait_queue *open_wait;
struct wait_queue *close_wait;
#endif
unsigned long char_time_usec; /* The time for 1 char, in usecs */
unsigned long flush_time_usec; /* How often we should flush */
unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */
unsigned long last_tx_active; /* Last tx time in jiffies */
unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */
unsigned long last_rx_active; /* Last rx time in jiffies */
int break_detected_cnt;
int errorcode;
#ifdef CONFIG_ETRAX_RS485
struct rs485_control rs485; /* RS-485 support */
#endif
};
/* this PORT is not in the standard serial.h. it's not actually used for
* anything since we only have one type of async serial-port anyway in this
* system.
*/
#define PORT_ETRAX 1
/*
* Events are used to schedule things to happen at timer-interrupt
* time, instead of at rs interrupt time.
*/
#define RS_EVENT_WRITE_WAKEUP 0
#endif /* __KERNEL__ */
#endif /* !_ETRAX_SERIAL_H */

View File

@@ -0,0 +1,822 @@
/*
* dz.c: Serial port driver for DECStations equiped
* with the DZ chipset.
*
* Copyright (C) 1998 Olivier A. D. Lebaillif
*
* Email: olivier.lebaillif@ifrsys.com
*
* [31-AUG-98] triemer
* Changed IRQ to use Harald's dec internals interrupts.h
* removed base_addr code - moving address assignment to setup.c
* Changed name of dz_init to rs_init to be consistent with tc code
* [13-NOV-98] triemer fixed code to receive characters
* after patches by harald to irq code.
* [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
* field from "current" - somewhere between 2.1.121 and 2.1.131
Qua Jun 27 15:02:26 BRT 2001
* [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
*
* Parts (C) 1999 David Airlie, airlied@linux.ie
* [07-SEP-99] Bugfixes
*
* [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
* Converted to new serial core
*/
#undef DEBUG_DZ
#include <linux/config.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/bootinfo.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/kn01.h>
#include <asm/dec/kn02.h>
#include <asm/dec/machtype.h>
#include <asm/dec/prom.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define CONSOLE_LINE (3) /* for definition of struct console */
#include "dz.h"
#define DZ_INTR_DEBUG 1
static char *dz_name = "DECstation DZ serial driver version ";
static char *dz_version = "1.02";
struct dz_port {
struct uart_port port;
unsigned int cflag;
};
static struct dz_port dz_ports[DZ_NB_PORT];
#ifdef DEBUG_DZ
/*
* debugging code to send out chars via prom
*/
static void debug_console(const char *s, int count)
{
unsigned i;
for (i = 0; i < count; i++) {
if (*s == 10)
prom_printf("%c", 13);
prom_printf("%c", *s++);
}
}
#endif
/*
* ------------------------------------------------------------
* dz_in () and dz_out ()
*
* These routines are used to access the registers of the DZ
* chip, hiding relocation differences between implementation.
* ------------------------------------------------------------
*/
static inline unsigned short dz_in(struct dz_port *dport, unsigned offset)
{
volatile unsigned short *addr =
(volatile unsigned short *) (dport->port.membase + offset);
return *addr;
}
static inline void dz_out(struct dz_port *dport, unsigned offset,
unsigned short value)
{
volatile unsigned short *addr =
(volatile unsigned short *) (dport->port.membase + offset);
*addr = value;
}
/*
* ------------------------------------------------------------
* rs_stop () and rs_start ()
*
* These routines are called before setting or resetting
* tty->stopped. They enable or disable transmitter interrupts,
* as necessary.
* ------------------------------------------------------------
*/
static void dz_stop_tx(struct uart_port *uport, unsigned int tty_stop)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned short tmp, mask = 1 << dport->port.line;
unsigned long flags;
spin_lock_irqsave(&dport->port.lock, flags);
tmp = dz_in(dport, DZ_TCR); /* read the TX flag */
tmp &= ~mask; /* clear the TX flag */
dz_out(dport, DZ_TCR, tmp);
spin_unlock_irqrestore(&dport->port.lock, flags);
}
static void dz_start_tx(struct uart_port *uport, unsigned int tty_start)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned short tmp, mask = 1 << dport->port.line;
unsigned long flags;
spin_lock_irqsave(&dport->port.lock, flags);
tmp = dz_in(dport, DZ_TCR); /* read the TX flag */
tmp |= mask; /* set the TX flag */
dz_out(dport, DZ_TCR, tmp);
spin_unlock_irqrestore(&dport->port.lock, flags);
}
static void dz_stop_rx(struct uart_port *uport)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
spin_lock_irqsave(&dport->port.lock, flags);
dport->cflag &= ~DZ_CREAD;
dz_out(dport, DZ_LPR, dport->cflag);
spin_unlock_irqrestore(&dport->port.lock, flags);
}
static void dz_enable_ms(struct uart_port *port)
{
/* nothing to do */
}
/*
* ------------------------------------------------------------
* Here starts the interrupt handling routines. All of the
* following subroutines are declared as inline and are folded
* into dz_interrupt. They were separated out for readability's
* sake.
*
* Note: rs_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
*
* make drivers/serial/dz.s
*
* and look at the resulting assemble code in dz.s.
*
* ------------------------------------------------------------
*/
/*
* ------------------------------------------------------------
* receive_char ()
*
* This routine deals with inputs from any lines.
* ------------------------------------------------------------
*/
static inline void dz_receive_chars(struct dz_port *dport)
{
struct tty_struct *tty = NULL;
struct uart_icount *icount;
int ignore = 0;
unsigned short status, tmp;
unsigned char ch, flag;
/* this code is going to be a problem...
the call to tty_flip_buffer is going to need
to be rethought...
*/
do {
status = dz_in(dport, DZ_RBUF);
/* punt so we don't get duplicate characters */
if (!(status & DZ_DVAL))
goto ignore_char;
ch = UCHAR(status); /* grab the char */
flag = TTY_NORMAL;
#if 0
if (info->is_console) {
if (ch == 0)
return; /* it's a break ... */
}
#endif
tty = dport->port.info->tty;/* now tty points to the proper dev */
icount = &dport->port.icount;
if (!tty)
break;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break;
icount->rx++;
/* keep track of the statistics */
if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
if (status & DZ_PERR) /* parity error */
icount->parity++;
else if (status & DZ_FERR) /* frame error */
icount->frame++;
if (status & DZ_OERR) /* overrun error */
icount->overrun++;
/* check to see if we should ignore the character
and mask off conditions that should be ignored
*/
if (status & dport->port.ignore_status_mask) {
if (++ignore > 100)
break;
goto ignore_char;
}
/* mask off the error conditions we want to ignore */
tmp = status & dport->port.read_status_mask;
if (tmp & DZ_PERR) {
flag = TTY_PARITY;
#ifdef DEBUG_DZ
debug_console("PERR\n", 5);
#endif
} else if (tmp & DZ_FERR) {
flag = TTY_FRAME;
#ifdef DEBUG_DZ
debug_console("FERR\n", 5);
#endif
}
if (tmp & DZ_OERR) {
#ifdef DEBUG_DZ
debug_console("OERR\n", 5);
#endif
tty_insert_flip_char(tty, ch, flag);
ch = 0;
flag = TTY_OVERRUN;
}
}
tty_insert_flip_char(tty, ch, flag);
ignore_char:
} while (status & DZ_DVAL);
if (tty)
tty_flip_buffer_push(tty);
}
/*
* ------------------------------------------------------------
* transmit_char ()
*
* This routine deals with outputs to any lines.
* ------------------------------------------------------------
*/
static inline void dz_transmit_chars(struct dz_port *dport)
{
struct circ_buf *xmit = &dport->port.info->xmit;
unsigned char tmp;
if (dport->port.x_char) { /* XON/XOFF chars */
dz_out(dport, DZ_TDR, dport->port.x_char);
dport->port.icount.tx++;
dport->port.x_char = 0;
return;
}
/* if nothing to do or stopped or hardware stopped */
if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
dz_stop_tx(&dport->port, 0);
return;
}
/*
* if something to do ... (rember the dz has no output fifo so we go
* one char at a time :-<
*/
tmp = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
dz_out(dport, DZ_TDR, tmp);
dport->port.icount.tx++;
if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
uart_write_wakeup(&dport->port);
/* Are we done */
if (uart_circ_empty(xmit))
dz_stop_tx(&dport->port, 0);
}
/*
* ------------------------------------------------------------
* check_modem_status ()
*
* Only valid for the MODEM line duh !
* ------------------------------------------------------------
*/
static inline void check_modem_status(struct dz_port *dport)
{
unsigned short status;
/* if not ne modem line just return */
if (dport->port.line != DZ_MODEM)
return;
status = dz_in(dport, DZ_MSR);
/* it's easy, since DSR2 is the only bit in the register */
if (status)
dport->port.icount.dsr++;
}
/*
* ------------------------------------------------------------
* dz_interrupt ()
*
* this is the main interrupt routine for the DZ chip.
* It deals with the multiple ports.
* ------------------------------------------------------------
*/
static irqreturn_t dz_interrupt(int irq, void *dev, struct pt_regs *regs)
{
struct dz_port *dport;
unsigned short status;
/* get the reason why we just got an irq */
status = dz_in((struct dz_port *)dev, DZ_CSR);
dport = &dz_ports[LINE(status)];
if (status & DZ_RDONE)
dz_receive_chars(dport);
if (status & DZ_TRDY)
dz_transmit_chars(dport);
/* FIXME: what about check modem status??? --rmk */
return IRQ_HANDLED;
}
/*
* -------------------------------------------------------------------
* Here ends the DZ interrupt routines.
* -------------------------------------------------------------------
*/
static unsigned int dz_get_mctrl(struct uart_port *uport)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
if (dport->port.line == DZ_MODEM) {
/*
* CHECKME: This is a guess from the other code... --rmk
*/
if (dz_in(dport, DZ_MSR) & DZ_MODEM_DSR)
mctrl &= ~TIOCM_DSR;
}
return mctrl;
}
static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned short tmp;
if (dport->port.line == DZ_MODEM) {
tmp = dz_in(dport, DZ_TCR);
if (mctrl & TIOCM_DTR)
tmp &= ~DZ_MODEM_DTR;
else
tmp |= DZ_MODEM_DTR;
dz_out(dport, DZ_TCR, tmp);
}
}
/*
* -------------------------------------------------------------------
* startup ()
*
* various initialization tasks
* -------------------------------------------------------------------
*/
static int dz_startup(struct uart_port *uport)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
unsigned short tmp;
/* The dz lines for the mouse/keyboard must be
* opened using their respective drivers.
*/
if ((dport->port.line == DZ_KEYBOARD) ||
(dport->port.line == DZ_MOUSE))
return -ENODEV;
spin_lock_irqsave(&dport->port.lock, flags);
/* enable the interrupt and the scanning */
tmp = dz_in(dport, DZ_CSR);
tmp |= DZ_RIE | DZ_TIE | DZ_MSE;
dz_out(dport, DZ_CSR, tmp);
spin_unlock_irqrestore(&dport->port.lock, flags);
return 0;
}
/*
* -------------------------------------------------------------------
* shutdown ()
*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
* -------------------------------------------------------------------
*/
static void dz_shutdown(struct uart_port *uport)
{
dz_stop_tx(uport, 0);
}
/*
* get_lsr_info - get line status register info
*
* Purpose: Let user call ioctl() to get info when the UART physically
* is emptied. On bus types like RS485, the transmitter must
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
static unsigned int dz_tx_empty(struct uart_port *uport)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned short status = dz_in(dport, DZ_LPR);
/* FIXME: this appears to be obviously broken --rmk. */
return status ? TIOCSER_TEMT : 0;
}
static void dz_break_ctl(struct uart_port *uport, int break_state)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
unsigned short tmp, mask = 1 << uport->line;
spin_lock_irqsave(&uport->lock, flags);
tmp = dz_in(dport, DZ_TCR);
if (break_state)
tmp |= mask;
else
tmp &= ~mask;
dz_out(dport, DZ_TCR, tmp);
spin_unlock_irqrestore(&uport->lock, flags);
}
static void dz_set_termios(struct uart_port *uport, struct termios *termios,
struct termios *old_termios)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
unsigned int cflag, baud;
cflag = dport->port.line;
switch (termios->c_cflag & CSIZE) {
case CS5:
cflag |= DZ_CS5;
break;
case CS6:
cflag |= DZ_CS6;
break;
case CS7:
cflag |= DZ_CS7;
break;
case CS8:
default:
cflag |= DZ_CS8;
}
if (termios->c_cflag & CSTOPB)
cflag |= DZ_CSTOPB;
if (termios->c_cflag & PARENB)
cflag |= DZ_PARENB;
if (termios->c_cflag & PARODD)
cflag |= DZ_PARODD;
baud = uart_get_baud_rate(uport, termios, old_termios, 50, 9600);
switch (baud) {
case 50:
cflag |= DZ_B50;
break;
case 75:
cflag |= DZ_B75;
break;
case 110:
cflag |= DZ_B110;
break;
case 134:
cflag |= DZ_B134;
break;
case 150:
cflag |= DZ_B150;
break;
case 300:
cflag |= DZ_B300;
break;
case 600:
cflag |= DZ_B600;
break;
case 1200:
cflag |= DZ_B1200;
break;
case 1800:
cflag |= DZ_B1800;
break;
case 2000:
cflag |= DZ_B2000;
break;
case 2400:
cflag |= DZ_B2400;
break;
case 3600:
cflag |= DZ_B3600;
break;
case 4800:
cflag |= DZ_B4800;
break;
case 7200:
cflag |= DZ_B7200;
break;
case 9600:
default:
cflag |= DZ_B9600;
}
if (termios->c_cflag & CREAD)
cflag |= DZ_RXENAB;
spin_lock_irqsave(&dport->port.lock, flags);
dz_out(dport, DZ_LPR, cflag);
dport->cflag = cflag;
/* setup accept flag */
dport->port.read_status_mask = DZ_OERR;
if (termios->c_iflag & INPCK)
dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
/* characters to ignore */
uport->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
spin_unlock_irqrestore(&dport->port.lock, flags);
}
static const char *dz_type(struct uart_port *port)
{
return "DZ";
}
static void dz_release_port(struct uart_port *port)
{
/* nothing to do */
}
static int dz_request_port(struct uart_port *port)
{
return 0;
}
static void dz_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_DZ;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int dz_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_DZ)
ret = -EINVAL;
if (ser->irq != port->irq)
ret = -EINVAL;
return ret;
}
static struct uart_ops dz_ops = {
.tx_empty = dz_tx_empty,
.get_mctrl = dz_get_mctrl,
.set_mctrl = dz_set_mctrl,
.stop_tx = dz_stop_tx,
.start_tx = dz_start_tx,
.stop_rx = dz_stop_rx,
.enable_ms = dz_enable_ms,
.break_ctl = dz_break_ctl,
.startup = dz_startup,
.shutdown = dz_shutdown,
.set_termios = dz_set_termios,
.type = dz_type,
.release_port = dz_release_port,
.request_port = dz_request_port,
.config_port = dz_config_port,
.verify_port = dz_verify_port,
};
static void __init dz_init_ports(void)
{
static int first = 1;
struct dz_port *dport;
unsigned long base;
int i;
if (!first)
return;
first = 0;
if (mips_machtype == MACH_DS23100 ||
mips_machtype == MACH_DS5100)
base = (unsigned long) KN01_DZ11_BASE;
else
base = (unsigned long) KN02_DZ11_BASE;
for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) {
spin_lock_init(&dport->port.lock);
dport->port.membase = (char *) base;
dport->port.iotype = SERIAL_IO_PORT;
dport->port.irq = dec_interrupt[DEC_IRQ_DZ11];
dport->port.line = i;
dport->port.fifosize = 1;
dport->port.ops = &dz_ops;
dport->port.flags = UPF_BOOT_AUTOCONF;
}
}
static void dz_reset(struct dz_port *dport)
{
dz_out(dport, DZ_CSR, DZ_CLR);
while (dz_in(dport, DZ_CSR) & DZ_CLR);
/* FIXME: cpu_relax? */
iob();
/* enable scanning */
dz_out(dport, DZ_CSR, DZ_MSE);
}
#ifdef CONFIG_SERIAL_DZ_CONSOLE
static void dz_console_put_char(struct dz_port *dport, unsigned char ch)
{
unsigned long flags;
int loops = 2500;
unsigned short tmp = ch;
/* this code sends stuff out to serial device - spinning its
wheels and waiting. */
spin_lock_irqsave(&dport->port.lock, flags);
/* spin our wheels */
while (((dz_in(dport, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--)
/* FIXME: cpu_relax, udelay? --rmk */
;
/* Actually transmit the character. */
dz_out(dport, DZ_TDR, tmp);
spin_unlock_irqrestore(&dport->port.lock, flags);
}
/*
* -------------------------------------------------------------------
* dz_console_print ()
*
* dz_console_print is registered for printk.
* The console must be locked when we get here.
* -------------------------------------------------------------------
*/
static void dz_console_print(struct console *cons,
const char *str,
unsigned int count)
{
struct dz_port *dport = &dz_ports[CONSOLE_LINE];
#ifdef DEBUG_DZ
prom_printf((char *) str);
#endif
while (count--) {
if (*str == '\n')
dz_console_put_char(dport, '\r');
dz_console_put_char(dport, *str++);
}
}
static int __init dz_console_setup(struct console *co, char *options)
{
struct dz_port *dport = &dz_ports[CONSOLE_LINE];
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
unsigned short mask, tmp;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
dz_reset(dport);
ret = uart_set_options(&dport->port, co, baud, parity, bits, flow);
if (ret == 0) {
mask = 1 << dport->port.line;
tmp = dz_in(dport, DZ_TCR); /* read the TX flag */
if (!(tmp & mask)) {
tmp |= mask; /* set the TX flag */
dz_out(dport, DZ_TCR, tmp);
}
}
return ret;
}
static struct console dz_sercons =
{
.name = "ttyS",
.write = dz_console_print,
.device = uart_console_device,
.setup = dz_console_setup,
.flags = CON_CONSDEV | CON_PRINTBUFFER,
.index = CONSOLE_LINE,
};
void __init dz_serial_console_init(void)
{
dz_init_ports();
register_console(&dz_sercons);
}
#define SERIAL_DZ_CONSOLE &dz_sercons
#else
#define SERIAL_DZ_CONSOLE NULL
#endif /* CONFIG_SERIAL_DZ_CONSOLE */
static struct uart_driver dz_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
#ifdef CONFIG_DEVFS
.dev_name = "tts/%d",
#else
.dev_name = "ttyS%d",
#endif
.major = TTY_MAJOR,
.minor = 64,
.nr = DZ_NB_PORT,
.cons = SERIAL_DZ_CONSOLE,
};
int __init dz_init(void)
{
unsigned long flags;
int ret, i;
printk("%s%s\n", dz_name, dz_version);
dz_init_ports();
save_flags(flags);
cli();
#ifndef CONFIG_SERIAL_DZ_CONSOLE
/* reset the chip */
dz_reset(&dz_ports[0]);
#endif
/* order matters here... the trick is that flags
is updated... in request_irq - to immediatedly obliterate
it is unwise. */
restore_flags(flags);
if (request_irq(dz_ports[0].port.irq, dz_interrupt,
SA_INTERRUPT, "DZ", &dz_ports[0]))
panic("Unable to register DZ interrupt");
ret = uart_register_driver(&dz_reg);
if (ret != 0)
return ret;
for (i = 0; i < DZ_NB_PORT; i++)
uart_add_one_port(&dz_reg, &dz_ports[i].port);
return ret;
}
MODULE_DESCRIPTION("DECstation DZ serial driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,118 @@
/*
* dz.h: Serial port driver for DECStations equiped
* with the DZ chipset.
*
* Copyright (C) 1998 Olivier A. D. Lebaillif
*
* Email: olivier.lebaillif@ifrsys.com
*
*/
#ifndef DZ_SERIAL_H
#define DZ_SERIAL_H
/*
* Definitions for the Control and Status Received.
*/
#define DZ_TRDY 0x8000 /* Transmitter empty */
#define DZ_TIE 0x4000 /* Transmitter Interrupt Enable */
#define DZ_RDONE 0x0080 /* Receiver data ready */
#define DZ_RIE 0x0040 /* Receive Interrupt Enable */
#define DZ_MSE 0x0020 /* Master Scan Enable */
#define DZ_CLR 0x0010 /* Master reset */
#define DZ_MAINT 0x0008 /* Loop Back Mode */
/*
* Definitions for the Received buffer.
*/
#define DZ_RBUF_MASK 0x00FF /* Data Mask in the Receive Buffer */
#define DZ_LINE_MASK 0x0300 /* Line Mask in the Receive Buffer */
#define DZ_DVAL 0x8000 /* Valid Data indicator */
#define DZ_OERR 0x4000 /* Overrun error indicator */
#define DZ_FERR 0x2000 /* Frame error indicator */
#define DZ_PERR 0x1000 /* Parity error indicator */
#define LINE(x) (x & DZ_LINE_MASK) >> 8 /* Get the line number from the input buffer */
#define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK)
/*
* Definitions for the Transmit Register.
*/
#define DZ_LINE_KEYBOARD 0x0001
#define DZ_LINE_MOUSE 0x0002
#define DZ_LINE_MODEM 0x0004
#define DZ_LINE_PRINTER 0x0008
#define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */
/*
* Definitions for the Modem Status Register.
*/
#define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */
/*
* Definitions for the Transmit Data Register.
*/
#define DZ_BRK0 0x0100 /* Break assertion for line 0 */
#define DZ_BRK1 0x0200 /* Break assertion for line 1 */
#define DZ_BRK2 0x0400 /* Break assertion for line 2 */
#define DZ_BRK3 0x0800 /* Break assertion for line 3 */
/*
* Definitions for the Line Parameter Register.
*/
#define DZ_KEYBOARD 0x0000 /* line 0 = keyboard */
#define DZ_MOUSE 0x0001 /* line 1 = mouse */
#define DZ_MODEM 0x0002 /* line 2 = modem */
#define DZ_PRINTER 0x0003 /* line 3 = printer */
#define DZ_CSIZE 0x0018 /* Number of bits per byte (mask) */
#define DZ_CS5 0x0000 /* 5 bits per byte */
#define DZ_CS6 0x0008 /* 6 bits per byte */
#define DZ_CS7 0x0010 /* 7 bits per byte */
#define DZ_CS8 0x0018 /* 8 bits per byte */
#define DZ_CSTOPB 0x0020 /* 2 stop bits instead of one */
#define DZ_PARENB 0x0040 /* Parity enable */
#define DZ_PARODD 0x0080 /* Odd parity instead of even */
#define DZ_CBAUD 0x0E00 /* Baud Rate (mask) */
#define DZ_B50 0x0000
#define DZ_B75 0x0100
#define DZ_B110 0x0200
#define DZ_B134 0x0300
#define DZ_B150 0x0400
#define DZ_B300 0x0500
#define DZ_B600 0x0600
#define DZ_B1200 0x0700
#define DZ_B1800 0x0800
#define DZ_B2000 0x0900
#define DZ_B2400 0x0A00
#define DZ_B3600 0x0B00
#define DZ_B4800 0x0C00
#define DZ_B7200 0x0D00
#define DZ_B9600 0x0E00
#define DZ_CREAD 0x1000 /* Enable receiver */
#define DZ_RXENAB 0x1000 /* enable receive char */
/*
* Addresses for the DZ registers
*/
#define DZ_CSR 0x00 /* Control and Status Register */
#define DZ_RBUF 0x08 /* Receive Buffer */
#define DZ_LPR 0x08 /* Line Parameters Register */
#define DZ_TCR 0x10 /* Transmitter Control Register */
#define DZ_MSR 0x18 /* Modem Status Register */
#define DZ_TDR 0x18 /* Transmit Data Register */
#define DZ_NB_PORT 4
#define DZ_XMIT_SIZE 4096 /* buffer size */
#define DZ_WAKEUP_CHARS DZ_XMIT_SIZE/4
#ifdef MODULE
int init_module (void)
void cleanup_module (void)
#endif
#endif /* DZ_SERIAL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,290 @@
/*
* icom.h
*
* Copyright (C) 2001 Michael Anderson, IBM Corporation
*
* Serial device driver include file.
*
* 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
*/
#include<linux/serial_core.h>
#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
static int icom_acfg_baud[] = {
300,
600,
900,
1200,
1800,
2400,
3600,
4800,
7200,
9600,
14400,
19200,
28800,
38400,
57600,
76800,
115200,
153600,
230400,
307200,
460800,
};
struct icom_regs {
u32 control; /* Adapter Control Register */
u32 interrupt; /* Adapter Interrupt Register */
u32 int_mask; /* Adapter Interrupt Mask Reg */
u32 int_pri; /* Adapter Interrupt Priority r */
u32 int_reg_b; /* Adapter non-masked Interrupt */
u32 resvd01;
u32 resvd02;
u32 resvd03;
u32 control_2; /* Adapter Control Register 2 */
u32 interrupt_2; /* Adapter Interrupt Register 2 */
u32 int_mask_2; /* Adapter Interrupt Mask 2 */
u32 int_pri_2; /* Adapter Interrupt Prior 2 */
u32 int_reg_2b; /* Adapter non-masked 2 */
};
struct func_dram {
u32 reserved[108]; /* 0-1B0 reserved by personality code */
u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */
u8 RcvStnAddr; /* 1B4 Receive Station Addr */
u8 IdleState; /* 1B5 Idle State */
u8 IdleMonitor; /* 1B6 Idle Monitor */
u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */
u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */
u8 StartXmitCmd; /* 1BC Start Xmit Command */
u8 HDLCConfigReg; /* 1BD Reserved */
u8 CauseCode; /* 1BE Cause code for fatal error */
u8 xchar; /* 1BF High priority send */
u32 reserved3; /* 1C0-1C3 Reserved */
u8 PrevCmdReg; /* 1C4 Reserved */
u8 CmdReg; /* 1C5 Command Register */
u8 async_config2; /* 1C6 Async Config Byte 2 */
u8 async_config3; /* 1C7 Async Config Byte 3 */
u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */
u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */
u8 misc_flags; /* 1DD misc flags */
#define V2_HARDWARE 0x40
#define ICOM_HDW_ACTIVE 0x01
u8 call_length; /* 1DE Phone #/CFI buff ln */
u8 call_length2; /* 1DF Upper byte (unused) */
u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */
u16 timer_value; /* 1E4-1E5 general timer value */
u8 timer_command; /* 1E6 general timer cmd */
u8 dce_command; /* 1E7 dce command reg */
u8 dce_cmd_status; /* 1E8 dce command stat */
u8 x21_r1_ioff; /* 1E9 dce ready counter */
u8 x21_r0_ioff; /* 1EA dce not ready ctr */
u8 x21_ralt_ioff; /* 1EB dce CNR counter */
u8 x21_r1_ion; /* 1EC dce ready I on ctr */
u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */
u8 ier; /* 1EE Interrupt Enable */
u8 isr; /* 1EF Input Signal Reg */
u8 osr; /* 1F0 Output Signal Reg */
u8 reset; /* 1F1 Reset/Reload Reg */
u8 disable; /* 1F2 Disable Reg */
u8 sync; /* 1F3 Sync Reg */
u8 error_stat; /* 1F4 Error Status */
u8 cable_id; /* 1F5 Cable ID */
u8 cs_length; /* 1F6 CS Load Length */
u8 mac_length; /* 1F7 Mac Load Length */
u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */
u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */
};
/*
* adapter defines and structures
*/
#define ICOM_CONTROL_START_A 0x00000008
#define ICOM_CONTROL_STOP_A 0x00000004
#define ICOM_CONTROL_START_B 0x00000002
#define ICOM_CONTROL_STOP_B 0x00000001
#define ICOM_CONTROL_START_C 0x00000008
#define ICOM_CONTROL_STOP_C 0x00000004
#define ICOM_CONTROL_START_D 0x00000002
#define ICOM_CONTROL_STOP_D 0x00000001
#define ICOM_IRAM_OFFSET 0x1000
#define ICOM_IRAM_SIZE 0x0C00
#define ICOM_DCE_IRAM_OFFSET 0x0A00
#define ICOM_CABLE_ID_VALID 0x01
#define ICOM_CABLE_ID_MASK 0xF0
#define ICOM_DISABLE 0x80
#define CMD_XMIT_RCV_ENABLE 0xC0
#define CMD_XMIT_ENABLE 0x40
#define CMD_RCV_DISABLE 0x00
#define CMD_RCV_ENABLE 0x80
#define CMD_RESTART 0x01
#define CMD_HOLD_XMIT 0x02
#define CMD_SND_BREAK 0x04
#define RS232_CABLE 0x06
#define V24_CABLE 0x0E
#define V35_CABLE 0x0C
#define V36_CABLE 0x02
#define NO_CABLE 0x00
#define START_DOWNLOAD 0x80
#define ICOM_INT_MASK_PRC_A 0x00003FFF
#define ICOM_INT_MASK_PRC_B 0x3FFF0000
#define ICOM_INT_MASK_PRC_C 0x00003FFF
#define ICOM_INT_MASK_PRC_D 0x3FFF0000
#define INT_RCV_COMPLETED 0x1000
#define INT_XMIT_COMPLETED 0x2000
#define INT_IDLE_DETECT 0x0800
#define INT_RCV_DISABLED 0x0400
#define INT_XMIT_DISABLED 0x0200
#define INT_RCV_XMIT_SHUTDOWN 0x0100
#define INT_FATAL_ERROR 0x0080
#define INT_CABLE_PULL 0x0020
#define INT_SIGNAL_CHANGE 0x0010
#define HDLC_PPP_PURE_ASYNC 0x02
#define HDLC_FF_FILL 0x00
#define HDLC_HDW_FLOW 0x01
#define START_XMIT 0x80
#define ICOM_ACFG_DRIVE1 0x20
#define ICOM_ACFG_NO_PARITY 0x00
#define ICOM_ACFG_PARITY_ENAB 0x02
#define ICOM_ACFG_PARITY_ODD 0x01
#define ICOM_ACFG_8BPC 0x00
#define ICOM_ACFG_7BPC 0x04
#define ICOM_ACFG_6BPC 0x08
#define ICOM_ACFG_5BPC 0x0C
#define ICOM_ACFG_1STOP_BIT 0x00
#define ICOM_ACFG_2STOP_BIT 0x10
#define ICOM_DTR 0x80
#define ICOM_RTS 0x40
#define ICOM_RI 0x08
#define ICOM_DSR 0x80
#define ICOM_DCD 0x20
#define ICOM_CTS 0x40
#define NUM_XBUFFS 1
#define NUM_RBUFFS 2
#define RCV_BUFF_SZ 0x0200
#define XMIT_BUFF_SZ 0x1000
struct statusArea {
/**********************************************/
/* Transmit Status Area */
/**********************************************/
struct xmit_status_area{
u32 leNext; /* Next entry in Little Endian on Adapter */
u32 leNextASD;
u32 leBuffer; /* Buffer for entry in LE for Adapter */
u16 leLengthASD;
u16 leOffsetASD;
u16 leLength; /* Length of data in segment */
u16 flags;
#define SA_FLAGS_DONE 0x0080 /* Done with Segment */
#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */
#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */
#define SA_FLAGS_READY_TO_XMIT 0x0800
#define SA_FLAGS_STAT_MASK 0x007F
} xmit[NUM_XBUFFS];
/**********************************************/
/* Receive Status Area */
/**********************************************/
struct {
u32 leNext; /* Next entry in Little Endian on Adapter */
u32 leNextASD;
u32 leBuffer; /* Buffer for entry in LE for Adapter */
u16 WorkingLength; /* size of segment */
u16 reserv01;
u16 leLength; /* Length of data in segment */
u16 flags;
#define SA_FL_RCV_DONE 0x0010 /* Data ready */
#define SA_FLAGS_OVERRUN 0x0040
#define SA_FLAGS_PARITY_ERROR 0x0080
#define SA_FLAGS_FRAME_ERROR 0x0001
#define SA_FLAGS_FRAME_TRUNC 0x0002
#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */
#define SA_FLAGS_RCV_MASK 0xFFE6
} rcv[NUM_RBUFFS];
};
struct icom_adapter;
#define ICOM_MAJOR 243
#define ICOM_MINOR_START 0
struct icom_port {
struct uart_port uart_port;
u8 imbed_modem;
#define ICOM_UNKNOWN 1
#define ICOM_RVX 2
#define ICOM_IMBED_MODEM 3
unsigned char cable_id;
unsigned char read_status_mask;
unsigned char ignore_status_mask;
unsigned long int_reg;
struct icom_regs *global_reg;
struct func_dram *dram;
int port;
struct statusArea *statStg;
dma_addr_t statStg_pci;
u32 *xmitRestart;
dma_addr_t xmitRestart_pci;
unsigned char *xmit_buf;
dma_addr_t xmit_buf_pci;
unsigned char *recv_buf;
dma_addr_t recv_buf_pci;
int next_rcv;
int put_length;
int status;
#define ICOM_PORT_ACTIVE 1 /* Port exists. */
#define ICOM_PORT_OFF 0 /* Port does not exist. */
int load_in_progress;
struct icom_adapter *adapter;
};
struct icom_adapter {
unsigned long base_addr;
unsigned long base_addr_pci;
unsigned char irq_number;
struct pci_dev *pci_dev;
struct icom_port port_info[4];
int index;
int version;
#define ADAPTER_V1 0x0001
#define ADAPTER_V2 0x0002
u32 subsystem_id;
#define FOUR_PORT_MODEL 0x0252
#define V2_TWO_PORTS_RVX 0x021A
#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251
int numb_ports;
struct list_head icom_adapter_entry;
struct kobject kobj;
};
/* prototype */
extern void iCom_sercons_init(void);
struct lookup_proc_table {
u32 *global_control_reg;
unsigned long processor_id;
};
struct lookup_int_table {
u32 *global_int_mask;
unsigned long processor_id;
};
#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000)

View File

@@ -0,0 +1,902 @@
/*
* linux/drivers/serial/imx.c
*
* Driver for Motorola IMX serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Author: Sascha Hauer <sascha@saschahauer.de>
* Copyright (C) 2004 Pengutronix
*
* 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
*
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_IMX_MAJOR 204
#define MINOR_START 41
#define NR_PORTS 2
#define IMX_ISR_PASS_LIMIT 256
/*
* This is the size of our serial port register set.
*/
#define UART_PORT_SIZE 0x100
/*
* This determines how often we check the modem status signals
* for any change. They generally aren't connected to an IRQ
* so we have to poll them. We also check immediately before
* filling the TX fifo incase CTS has been dropped.
*/
#define MCTRL_TIMEOUT (250*HZ/1000)
#define DRIVER_NAME "IMX-uart"
struct imx_port {
struct uart_port port;
struct timer_list timer;
unsigned int old_status;
int txirq,rxirq;
};
/*
* Handle any change of modem status signal since we were last called.
*/
static void imx_mctrl_check(struct imx_port *sport)
{
unsigned int status, changed;
status = sport->port.ops->get_mctrl(&sport->port);
changed = status ^ sport->old_status;
if (changed == 0)
return;
sport->old_status = status;
if (changed & TIOCM_RI)
sport->port.icount.rng++;
if (changed & TIOCM_DSR)
sport->port.icount.dsr++;
if (changed & TIOCM_CAR)
uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
if (changed & TIOCM_CTS)
uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
wake_up_interruptible(&sport->port.info->delta_msr_wait);
}
/*
* This is our per-port timeout handler, for checking the
* modem status signals.
*/
static void imx_timeout(unsigned long data)
{
struct imx_port *sport = (struct imx_port *)data;
unsigned long flags;
if (sport->port.info) {
spin_lock_irqsave(&sport->port.lock, flags);
imx_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
}
}
/*
* interrupts disabled on entry
*/
static void imx_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
struct imx_port *sport = (struct imx_port *)port;
UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN;
}
/*
* interrupts disabled on entry
*/
static void imx_stop_rx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
UCR2((u32)sport->port.membase) &= ~UCR2_RXEN;
}
/*
* Set the modem control timer to fire immediately.
*/
static void imx_enable_ms(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
mod_timer(&sport->timer, jiffies);
}
static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.info->xmit;
do {
/* send xmit->buf[xmit->tail]
* out the port here */
URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) &
(UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (!(UTS((u32)sport->port.membase) & UTS_TXFULL));
if (uart_circ_empty(xmit))
imx_stop_tx(&sport->port, 0);
}
/*
* interrupts disabled on entry
*/
static void imx_start_tx(struct uart_port *port, unsigned int tty_start)
{
struct imx_port *sport = (struct imx_port *)port;
UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN;
if(UTS((u32)sport->port.membase) & UTS_TXEMPTY)
imx_transmit_buffer(sport);
}
static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs)
{
struct imx_port *sport = (struct imx_port *)dev_id;
struct circ_buf *xmit = &sport->port.info->xmit;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock,flags);
if (sport->port.x_char)
{
/* Send next char */
URTX0((u32)sport->port.membase) = sport->port.x_char;
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
imx_stop_tx(&sport->port, 0);
goto out;
}
imx_transmit_buffer(sport);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
out:
spin_unlock_irqrestore(&sport->port.lock,flags);
return IRQ_HANDLED;
}
static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs)
{
struct imx_port *sport = dev_id;
unsigned int rx,flg,ignored = 0;
struct tty_struct *tty = sport->port.info->tty;
unsigned long flags;
rx = URXD0((u32)sport->port.membase);
spin_lock_irqsave(&sport->port.lock,flags);
do {
flg = TTY_NORMAL;
sport->port.icount.rx++;
if( USR2((u32)sport->port.membase) & USR2_BRCD ) {
USR2((u32)sport->port.membase) |= USR2_BRCD;
if(uart_handle_break(&sport->port))
goto ignore_char;
}
if (uart_handle_sysrq_char
(&sport->port, (unsigned char)rx, regs))
goto ignore_char;
if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) )
goto handle_error;
error_return:
tty_insert_flip_char(tty, rx, flg);
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
goto out;
ignore_char:
rx = URXD0((u32)sport->port.membase);
} while(rx & URXD_CHARRDY);
out:
spin_unlock_irqrestore(&sport->port.lock,flags);
tty_flip_buffer_push(tty);
return IRQ_HANDLED;
handle_error:
if (rx & URXD_PRERR)
sport->port.icount.parity++;
else if (rx & URXD_FRMERR)
sport->port.icount.frame++;
if (rx & URXD_OVRRUN)
sport->port.icount.overrun++;
if (rx & sport->port.ignore_status_mask) {
if (++ignored > 100)
goto out;
goto ignore_char;
}
rx &= sport->port.read_status_mask;
if (rx & URXD_PRERR)
flg = TTY_PARITY;
else if (rx & URXD_FRMERR)
flg = TTY_FRAME;
if (rx & URXD_OVRRUN)
flg = TTY_OVERRUN;
#ifdef SUPPORT_SYSRQ
sport->port.sysrq = 0;
#endif
goto error_return;
}
/*
* Return TIOCSER_TEMT when transmitter is not busy.
*/
static unsigned int imx_tx_empty(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
return USR2((u32)sport->port.membase) & USR2_TXDC ? TIOCSER_TEMT : 0;
}
static unsigned int imx_get_mctrl(struct uart_port *port)
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
/*
* Interrupts always disabled.
*/
static void imx_break_ctl(struct uart_port *port, int break_state)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
if ( break_state != 0 )
UCR1((u32)sport->port.membase) |= UCR1_SNDBRK;
else
UCR1((u32)sport->port.membase) &= ~UCR1_SNDBRK;
spin_unlock_irqrestore(&sport->port.lock, flags);
}
#define TXTL 2 /* reset default */
#define RXTL 1 /* reset default */
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval;
unsigned int val;
unsigned long flags;
/* set receiver / transmitter trigger level. We assume
* that RFDIV has been set by the arch setup or by the bootloader.
*/
val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) | TXTL<<10 | RXTL;
UFCR((u32)sport->port.membase) = val;
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
*/
UCR4((u32)sport->port.membase) &= ~UCR4_DREN;
/*
* Allocate the IRQ
*/
retval = request_irq(sport->rxirq, imx_rxint, 0,
DRIVER_NAME, sport);
if (retval) goto error_out2;
retval = request_irq(sport->txirq, imx_txint, 0,
"imx-uart", sport);
if (retval) goto error_out1;
/*
* Finally, clear and enable interrupts
*/
UCR1((u32)sport->port.membase) |=
(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_UARTEN);
UCR2((u32)sport->port.membase) |= (UCR2_RXEN | UCR2_TXEN);
/*
* Enable modem status interrupts
*/
spin_lock_irqsave(&sport->port.lock,flags);
imx_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock,flags);
return 0;
error_out1:
free_irq(sport->rxirq, sport);
error_out2:
free_irq(sport->txirq, sport);
return retval;
}
static void imx_shutdown(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
/*
* Stop our timer.
*/
del_timer_sync(&sport->timer);
/*
* Free the interrupts
*/
free_irq(sport->txirq, sport);
free_irq(sport->rxirq, sport);
/*
* Disable all interrupts, port and break condition.
*/
UCR1((u32)sport->port.membase) &=
~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_UARTEN);
}
static void
imx_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
/*
* If we don't support modem control lines, don't allow
* these to be set.
*/
if (0) {
termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
termios->c_cflag |= CLOCAL;
}
/*
* We only support CS7 and CS8.
*/
while ((termios->c_cflag & CSIZE) != CS7 &&
(termios->c_cflag & CSIZE) != CS8) {
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= old_csize;
old_csize = CS8;
}
if ((termios->c_cflag & CSIZE) == CS8)
ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
else
ucr2 = UCR2_SRST | UCR2_IRTS;
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
if (termios->c_cflag & PARENB) {
ucr2 |= UCR2_PREN;
if (!(termios->c_cflag & PARODD))
ucr2 |= UCR2_PROE;
}
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&sport->port.lock, flags);
sport->port.read_status_mask = 0;
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
if (termios->c_iflag & (BRKINT | PARMRK))
sport->port.read_status_mask |= URXD_BRK;
/*
* Characters to ignore
*/
sport->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= URXD_PRERR;
if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |= URXD_BRK;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= URXD_OVRRUN;
}
del_timer_sync(&sport->timer);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
/*
* disable interrupts and drain transmitter
*/
old_ucr1 = UCR1((u32)sport->port.membase);
UCR1((u32)sport->port.membase) &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN);
while ( !(USR2((u32)sport->port.membase) & USR2_TXDC))
barrier();
/* then, disable everything */
old_txrxen = UCR2((u32)sport->port.membase) & ( UCR2_TXEN | UCR2_RXEN );
UCR2((u32)sport->port.membase) &= ~( UCR2_TXEN | UCR2_RXEN);
/* set the parity, stop bits and data size */
UCR2((u32)sport->port.membase) = ucr2;
/* set the baud rate. We assume uartclk = 16 MHz
*
* baud * 16 UBIR - 1
* --------- = --------
* uartclk UBMR - 1
*/
UBIR((u32)sport->port.membase) = (baud / 100) - 1;
UBMR((u32)sport->port.membase) = 10000 - 1;
UCR1((u32)sport->port.membase) = old_ucr1;
UCR2((u32)sport->port.membase) |= old_txrxen;
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static const char *imx_type(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
return sport->port.type == PORT_IMX ? "IMX" : NULL;
}
/*
* Release the memory region(s) being used by 'port'.
*/
static void imx_release_port(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
}
/*
* Request the memory region(s) being used by 'port'.
*/
static int imx_request_port(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
"imx-uart") != NULL ? 0 : -EBUSY;
}
/*
* Configure/autoconfigure the port.
*/
static void imx_config_port(struct uart_port *port, int flags)
{
struct imx_port *sport = (struct imx_port *)port;
if (flags & UART_CONFIG_TYPE &&
imx_request_port(&sport->port) == 0)
sport->port.type = PORT_IMX;
}
/*
* Verify the new serial_struct (for TIOCSSERIAL).
* The only change we allow are to the flags and type, and
* even then only between PORT_IMX and PORT_UNKNOWN
*/
static int
imx_verify_port(struct uart_port *port, struct serial_struct *ser)
{
struct imx_port *sport = (struct imx_port *)port;
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
ret = -EINVAL;
if (sport->port.irq != ser->irq)
ret = -EINVAL;
if (ser->io_type != UPIO_MEM)
ret = -EINVAL;
if (sport->port.uartclk / 16 != ser->baud_base)
ret = -EINVAL;
if ((void *)sport->port.mapbase != ser->iomem_base)
ret = -EINVAL;
if (sport->port.iobase != ser->port)
ret = -EINVAL;
if (ser->hub6 != 0)
ret = -EINVAL;
return ret;
}
static struct uart_ops imx_pops = {
.tx_empty = imx_tx_empty,
.set_mctrl = imx_set_mctrl,
.get_mctrl = imx_get_mctrl,
.stop_tx = imx_stop_tx,
.start_tx = imx_start_tx,
.stop_rx = imx_stop_rx,
.enable_ms = imx_enable_ms,
.break_ctl = imx_break_ctl,
.startup = imx_startup,
.shutdown = imx_shutdown,
.set_termios = imx_set_termios,
.type = imx_type,
.release_port = imx_release_port,
.request_port = imx_request_port,
.config_port = imx_config_port,
.verify_port = imx_verify_port,
};
static struct imx_port imx_ports[] = {
{
.txirq = UART1_MINT_TX,
.rxirq = UART1_MINT_RX,
.port = {
.type = PORT_IMX,
.iotype = SERIAL_IO_MEM,
.membase = (void *)IMX_UART1_BASE,
.mapbase = IMX_UART1_BASE, /* FIXME */
.irq = UART1_MINT_RX,
.uartclk = 16000000,
.fifosize = 8,
.flags = ASYNC_BOOT_AUTOCONF,
.ops = &imx_pops,
.line = 0,
},
}, {
.txirq = UART2_MINT_TX,
.rxirq = UART2_MINT_RX,
.port = {
.type = PORT_IMX,
.iotype = SERIAL_IO_MEM,
.membase = (void *)IMX_UART2_BASE,
.mapbase = IMX_UART2_BASE, /* FIXME */
.irq = UART2_MINT_RX,
.uartclk = 16000000,
.fifosize = 8,
.flags = ASYNC_BOOT_AUTOCONF,
.ops = &imx_pops,
.line = 1,
},
}
};
/*
* Setup the IMX serial ports.
* Note also that we support "console=ttySMXx" where "x" is either 0 or 1.
* Which serial port this ends up being depends on the machine you're
* running this kernel on. I'm not convinced that this is a good idea,
* but that's the way it traditionally works.
*
*/
static void __init imx_init_ports(void)
{
static int first = 1;
int i;
if (!first)
return;
first = 0;
for (i = 0; i < ARRAY_SIZE(imx_ports); i++) {
init_timer(&imx_ports[i].timer);
imx_ports[i].timer.function = imx_timeout;
imx_ports[i].timer.data = (unsigned long)&imx_ports[i];
}
imx_gpio_mode(PC9_PF_UART1_CTS);
imx_gpio_mode(PC10_PF_UART1_RTS);
imx_gpio_mode(PC11_PF_UART1_TXD);
imx_gpio_mode(PC12_PF_UART1_RXD);
imx_gpio_mode(PB28_PF_UART2_CTS);
imx_gpio_mode(PB29_PF_UART2_RTS);
imx_gpio_mode(PB30_PF_UART2_TXD);
imx_gpio_mode(PB31_PF_UART2_RXD);
#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart
* is implemented.
*/
imx_gpio_mode(PD7_AF_UART2_DTR);
imx_gpio_mode(PD8_AF_UART2_DCD);
imx_gpio_mode(PD9_AF_UART2_RI);
imx_gpio_mode(PD10_AF_UART2_DSR);
#endif
}
#ifdef CONFIG_SERIAL_IMX_CONSOLE
/*
* Interrupts are disabled on entering
*/
static void
imx_console_write(struct console *co, const char *s, unsigned int count)
{
struct imx_port *sport = &imx_ports[co->index];
unsigned int old_ucr1, old_ucr2, i;
/*
* First, save UCR1/2 and then disable interrupts
*/
old_ucr1 = UCR1((u32)sport->port.membase);
old_ucr2 = UCR2((u32)sport->port.membase);
UCR1((u32)sport->port.membase) =
(old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN)
& ~(UCR1_TXMPTYEN | UCR1_RRDYEN);
UCR2((u32)sport->port.membase) = old_ucr2 | UCR2_TXEN;
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
while ((UTS((u32)sport->port.membase) & UTS_TXFULL))
barrier();
URTX0((u32)sport->port.membase) = s[i];
if (s[i] == '\n') {
while ((UTS((u32)sport->port.membase) & UTS_TXFULL))
barrier();
URTX0((u32)sport->port.membase) = '\r';
}
}
/*
* Finally, wait for transmitter to become empty
* and restore UCR1/2
*/
while (!(USR2((u32)sport->port.membase) & USR2_TXDC));
UCR1((u32)sport->port.membase) = old_ucr1;
UCR2((u32)sport->port.membase) = old_ucr2;
}
/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
*/
static void __init
imx_console_get_options(struct imx_port *sport, int *baud,
int *parity, int *bits)
{
if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
/* ok, the port was enabled */
unsigned int ucr2, ubir,ubmr, uartclk;
ucr2 = UCR2((u32)sport->port.membase);
*parity = 'n';
if (ucr2 & UCR2_PREN) {
if (ucr2 & UCR2_PROE)
*parity = 'o';
else
*parity = 'e';
}
if (ucr2 & UCR2_WS)
*bits = 8;
else
*bits = 7;
ubir = UBIR((u32)sport->port.membase) & 0xffff;
ubmr = UBMR((u32)sport->port.membase) & 0xffff;
uartclk = sport->port.uartclk;
*baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1);
}
}
static int __init
imx_console_setup(struct console *co, char *options)
{
struct imx_port *sport;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
co->index = 0;
sport = &imx_ports[co->index];
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
imx_console_get_options(sport, &baud, &parity, &bits);
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
}
extern struct uart_driver imx_reg;
static struct console imx_console = {
.name = "ttySMX",
.write = imx_console_write,
.device = uart_console_device,
.setup = imx_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &imx_reg,
};
static int __init imx_rs_console_init(void)
{
imx_init_ports();
register_console(&imx_console);
return 0;
}
console_initcall(imx_rs_console_init);
#define IMX_CONSOLE &imx_console
#else
#define IMX_CONSOLE NULL
#endif
static struct uart_driver imx_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = "ttySMX",
.devfs_name = "ttsmx/",
.major = SERIAL_IMX_MAJOR,
.minor = MINOR_START,
.nr = ARRAY_SIZE(imx_ports),
.cons = IMX_CONSOLE,
};
static int serial_imx_suspend(struct device *_dev, u32 state, u32 level)
{
struct imx_port *sport = dev_get_drvdata(_dev);
if (sport && level == SUSPEND_DISABLE)
uart_suspend_port(&imx_reg, &sport->port);
return 0;
}
static int serial_imx_resume(struct device *_dev, u32 level)
{
struct imx_port *sport = dev_get_drvdata(_dev);
if (sport && level == RESUME_ENABLE)
uart_resume_port(&imx_reg, &sport->port);
return 0;
}
static int serial_imx_probe(struct device *_dev)
{
struct platform_device *dev = to_platform_device(_dev);
imx_ports[dev->id].port.dev = _dev;
uart_add_one_port(&imx_reg, &imx_ports[dev->id].port);
dev_set_drvdata(_dev, &imx_ports[dev->id]);
return 0;
}
static int serial_imx_remove(struct device *_dev)
{
struct imx_port *sport = dev_get_drvdata(_dev);
dev_set_drvdata(_dev, NULL);
if (sport)
uart_remove_one_port(&imx_reg, &sport->port);
return 0;
}
static struct device_driver serial_imx_driver = {
.name = "imx-uart",
.bus = &platform_bus_type,
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.suspend = serial_imx_suspend,
.resume = serial_imx_resume,
};
static int __init imx_serial_init(void)
{
int ret;
printk(KERN_INFO "Serial: IMX driver\n");
imx_init_ports();
ret = uart_register_driver(&imx_reg);
if (ret)
return ret;
ret = driver_register(&serial_imx_driver);
if (ret != 0)
uart_unregister_driver(&imx_reg);
return 0;
}
static void __exit imx_serial_exit(void)
{
uart_unregister_driver(&imx_reg);
}
module_init(imx_serial_init);
module_exit(imx_serial_exit);
MODULE_AUTHOR("Sascha Hauer");
MODULE_DESCRIPTION("IMX generic serial port driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,281 @@
#ifndef _IP22_ZILOG_H
#define _IP22_ZILOG_H
#include <asm/byteorder.h>
struct zilog_channel {
#ifdef __BIG_ENDIAN
volatile unsigned char unused0[3];
volatile unsigned char control;
volatile unsigned char unused1[3];
volatile unsigned char data;
#else /* __LITTLE_ENDIAN */
volatile unsigned char control;
volatile unsigned char unused0[3];
volatile unsigned char data;
volatile unsigned char unused1[3];
#endif
};
struct zilog_layout {
struct zilog_channel channelB;
struct zilog_channel channelA;
};
#define NUM_ZSREGS 16
/* Conversion routines to/from brg time constants from/to bits
* per second.
*/
#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
/* The Zilog register set */
#define FLAG 0x7e
/* Write Register 0 */
#define R0 0 /* Register selects */
#define R1 1
#define R2 2
#define R3 3
#define R4 4
#define R5 5
#define R6 6
#define R7 7
#define R8 8
#define R9 9
#define R10 10
#define R11 11
#define R12 12
#define R13 13
#define R14 14
#define R15 15
#define NULLCODE 0 /* Null Code */
#define POINT_HIGH 0x8 /* Select upper half of registers */
#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
#define SEND_ABORT 0x18 /* HDLC Abort */
#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
#define RES_Tx_P 0x28 /* Reset TxINT Pending */
#define ERR_RES 0x30 /* Error Reset */
#define RES_H_IUS 0x38 /* Reset highest IUS */
#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
#define RES_EOM_L 0xC0 /* Reset EOM latch */
/* Write Register 1 */
#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
#define TxINT_ENAB 0x2 /* Tx Int Enable */
#define PAR_SPEC 0x4 /* Parity is special condition */
#define RxINT_DISAB 0 /* Rx Int Disable */
#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
#define INT_ERR_Rx 0x18 /* Int on error only */
#define RxINT_MASK 0x18
#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
/* Write Register #2 (Interrupt Vector) */
/* Write Register 3 */
#define RxENAB 0x1 /* Rx Enable */
#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
#define ENT_HM 0x10 /* Enter Hunt Mode */
#define AUTO_ENAB 0x20 /* Auto Enables */
#define Rx5 0x0 /* Rx 5 Bits/Character */
#define Rx7 0x40 /* Rx 7 Bits/Character */
#define Rx6 0x80 /* Rx 6 Bits/Character */
#define Rx8 0xc0 /* Rx 8 Bits/Character */
#define RxN_MASK 0xc0
/* Write Register 4 */
#define PAR_ENAB 0x1 /* Parity Enable */
#define PAR_EVEN 0x2 /* Parity Even/Odd* */
#define SYNC_ENAB 0 /* Sync Modes Enable */
#define SB1 0x4 /* 1 stop bit/char */
#define SB15 0x8 /* 1.5 stop bits/char */
#define SB2 0xc /* 2 stop bits/char */
#define MONSYNC 0 /* 8 Bit Sync character */
#define BISYNC 0x10 /* 16 bit sync character */
#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
#define EXTSYNC 0x30 /* External Sync Mode */
#define X1CLK 0x0 /* x1 clock mode */
#define X16CLK 0x40 /* x16 clock mode */
#define X32CLK 0x80 /* x32 clock mode */
#define X64CLK 0xC0 /* x64 clock mode */
#define XCLK_MASK 0xC0
/* Write Register 5 */
#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
#define RTS 0x2 /* RTS */
#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
#define TxENAB 0x8 /* Tx Enable */
#define SND_BRK 0x10 /* Send Break */
#define Tx5 0x0 /* Tx 5 bits (or less)/character */
#define Tx7 0x20 /* Tx 7 bits/character */
#define Tx6 0x40 /* Tx 6 bits/character */
#define Tx8 0x60 /* Tx 8 bits/character */
#define TxN_MASK 0x60
#define DTR 0x80 /* DTR */
/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
/* Write Register 8 (transmit buffer) */
/* Write Register 9 (Master interrupt control) */
#define VIS 1 /* Vector Includes Status */
#define NV 2 /* No Vector */
#define DLC 4 /* Disable Lower Chain */
#define MIE 8 /* Master Interrupt Enable */
#define STATHI 0x10 /* Status high */
#define NORESET 0 /* No reset on write to R9 */
#define CHRB 0x40 /* Reset channel B */
#define CHRA 0x80 /* Reset channel A */
#define FHWRES 0xc0 /* Force hardware reset */
/* Write Register 10 (misc control bits) */
#define BIT6 1 /* 6 bit/8bit sync */
#define LOOPMODE 2 /* SDLC Loop mode */
#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
#define MARKIDLE 8 /* Mark/flag on idle */
#define GAOP 0x10 /* Go active on poll */
#define NRZ 0 /* NRZ mode */
#define NRZI 0x20 /* NRZI mode */
#define FM1 0x40 /* FM1 (transition = 1) */
#define FM0 0x60 /* FM0 (transition = 0) */
#define CRCPS 0x80 /* CRC Preset I/O */
/* Write Register 11 (Clock Mode control) */
#define TRxCXT 0 /* TRxC = Xtal output */
#define TRxCTC 1 /* TRxC = Transmit clock */
#define TRxCBR 2 /* TRxC = BR Generator Output */
#define TRxCDP 3 /* TRxC = DPLL output */
#define TRxCOI 4 /* TRxC O/I */
#define TCRTxCP 0 /* Transmit clock = RTxC pin */
#define TCTRxCP 8 /* Transmit clock = TRxC pin */
#define TCBR 0x10 /* Transmit clock = BR Generator output */
#define TCDPLL 0x18 /* Transmit clock = DPLL output */
#define RCRTxCP 0 /* Receive clock = RTxC pin */
#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
#define RCBR 0x40 /* Receive clock = BR Generator output */
#define RCDPLL 0x60 /* Receive clock = DPLL output */
#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
/* Write Register 12 (lower byte of baud rate generator time constant) */
/* Write Register 13 (upper byte of baud rate generator time constant) */
/* Write Register 14 (Misc control bits) */
#define BRENAB 1 /* Baud rate generator enable */
#define BRSRC 2 /* Baud rate generator source */
#define DTRREQ 4 /* DTR/Request function */
#define AUTOECHO 8 /* Auto Echo */
#define LOOPBAK 0x10 /* Local loopback */
#define SEARCH 0x20 /* Enter search mode */
#define RMC 0x40 /* Reset missing clock */
#define DISDPLL 0x60 /* Disable DPLL */
#define SSBR 0x80 /* Set DPLL source = BR generator */
#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
#define SFMM 0xc0 /* Set FM mode */
#define SNRZI 0xe0 /* Set NRZI mode */
/* Write Register 15 (external/status interrupt control) */
#define ZCIE 2 /* Zero count IE */
#define DCDIE 8 /* DCD IE */
#define SYNCIE 0x10 /* Sync/hunt IE */
#define CTSIE 0x20 /* CTS IE */
#define TxUIE 0x40 /* Tx Underrun/EOM IE */
#define BRKIE 0x80 /* Break/Abort IE */
/* Read Register 0 */
#define Rx_CH_AV 0x1 /* Rx Character Available */
#define ZCOUNT 0x2 /* Zero count */
#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
#define DCD 0x8 /* DCD */
#define SYNC 0x10 /* Sync/hunt */
#define CTS 0x20 /* CTS */
#define TxEOM 0x40 /* Tx underrun */
#define BRK_ABRT 0x80 /* Break/Abort */
/* Read Register 1 */
#define ALL_SNT 0x1 /* All sent */
/* Residue Data for 8 Rx bits/char programmed */
#define RES3 0x8 /* 0/3 */
#define RES4 0x4 /* 0/4 */
#define RES5 0xc /* 0/5 */
#define RES6 0x2 /* 0/6 */
#define RES7 0xa /* 0/7 */
#define RES8 0x6 /* 0/8 */
#define RES18 0xe /* 1/8 */
#define RES28 0x0 /* 2/8 */
/* Special Rx Condition Interrupts */
#define PAR_ERR 0x10 /* Parity error */
#define Rx_OVR 0x20 /* Rx Overrun Error */
#define CRC_ERR 0x40 /* CRC/Framing Error */
#define END_FR 0x80 /* End of Frame (SDLC) */
/* Read Register 2 (channel b only) - Interrupt vector */
#define CHB_Tx_EMPTY 0x00
#define CHB_EXT_STAT 0x02
#define CHB_Rx_AVAIL 0x04
#define CHB_SPECIAL 0x06
#define CHA_Tx_EMPTY 0x08
#define CHA_EXT_STAT 0x0a
#define CHA_Rx_AVAIL 0x0c
#define CHA_SPECIAL 0x0e
#define STATUS_MASK 0x0e
/* Read Register 3 (interrupt pending register) ch a only */
#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
#define CHBTxIP 0x2 /* Channel B Tx IP */
#define CHBRxIP 0x4 /* Channel B Rx IP */
#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
#define CHATxIP 0x10 /* Channel A Tx IP */
#define CHARxIP 0x20 /* Channel A Rx IP */
/* Read Register 8 (receive data register) */
/* Read Register 10 (misc status bits) */
#define ONLOOP 2 /* On loop */
#define LOOPSEND 0x10 /* Loop sending */
#define CLK2MIS 0x40 /* Two clocks missing */
#define CLK1MIS 0x80 /* One clock missing */
/* Read Register 12 (lower byte of baud rate generator constant) */
/* Read Register 13 (upper byte of baud rate generator constant) */
/* Read Register 15 (value of WR 15) */
/* Misc macros */
#define ZS_CLEARERR(channel) do { writeb(ERR_RES, &channel->control); \
udelay(5); } while(0)
#define ZS_CLEARSTAT(channel) do { writeb(RES_EXT_INT, &channel->control); \
udelay(5); } while(0)
#define ZS_CLEARFIFO(channel) do { readb(&channel->data); \
udelay(2); \
readb(&channel->data); \
udelay(2); \
readb(&channel->data); \
udelay(2); } while(0)
#endif /* _IP22_ZILOG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
/*
* m32r_sio.h
*
* Driver for M32R serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
* Based on drivers/serial/8250.h.
*
* Copyright (C) 2001 Russell King.
* Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
*
* 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/config.h>
struct m32r_sio_probe {
struct module *owner;
int (*pci_init_one)(struct pci_dev *dev);
void (*pci_remove_one)(struct pci_dev *dev);
void (*pnp_init)(void);
};
int m32r_sio_register_probe(struct m32r_sio_probe *probe);
void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
void m32r_sio_get_irq_map(unsigned int *map);
void m32r_sio_suspend_port(int line);
void m32r_sio_resume_port(int line);
struct old_serial_port {
unsigned int uart;
unsigned int baud_base;
unsigned int port;
unsigned int irq;
unsigned int flags;
unsigned char hub6;
unsigned char io_type;
unsigned char *iomem_base;
unsigned short iomem_reg_shift;
};
#define _INLINE_ inline
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#ifdef CONFIG_SERIAL_SIO_SHARE_IRQ
#define M32R_SIO_SHARE_IRQS 1
#else
#define M32R_SIO_SHARE_IRQS 0
#endif

View File

@@ -0,0 +1,343 @@
/*
* m32r_sio_reg.h
*
* Copyright (C) 1992, 1994 by Theodore Ts'o.
* Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
*
* Redistribution of this file is permitted under the terms of the GNU
* Public License (GPL)
*
* These are the UART port assignments, expressed as offsets from the base
* register. These assignments should hold for any serial port based on
* a 8250, 16450, or 16550(A).
*/
#ifndef _M32R_SIO_REG_H
#define _M32R_SIO_REG_H
#include <linux/config.h>
#ifdef CONFIG_SERIAL_M32R_PLDSIO
#define SIOCR 0x000
#define SIOMOD0 0x002
#define SIOMOD1 0x004
#define SIOSTS 0x006
#define SIOTRCR 0x008
#define SIOBAUR 0x00a
// #define SIORBAUR 0x018
#define SIOTXB 0x00c
#define SIORXB 0x00e
#define UART_RX ((unsigned long) PLD_ESIO0RXB)
/* In: Receive buffer (DLAB=0) */
#define UART_TX ((unsigned long) PLD_ESIO0TXB)
/* Out: Transmit buffer (DLAB=0) */
#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx
* In: Fifo count
* Out: Fifo custom trigger levels
* XR16C85x only */
#define UART_DLM 0 /* Out: Divisor Latch High (DLAB=1) */
#define UART_IER ((unsigned long) PLD_ESIO0INTCR)
/* Out: Interrupt Enable Register */
#define UART_FCTR 0 /* (LCR=BF) Feature Control Register
* XR16C85x only */
#define UART_IIR 0 /* In: Interrupt ID Register */
#define UART_FCR 0 /* Out: FIFO Control Register */
#define UART_EFR 0 /* I/O: Extended Features Register */
/* (DLAB=1, 16C660 only) */
#define UART_LCR 0 /* Out: Line Control Register */
#define UART_MCR 0 /* Out: Modem Control Register */
#define UART_LSR ((unsigned long) PLD_ESIO0STS)
/* In: Line Status Register */
#define UART_MSR 0 /* In: Modem Status Register */
#define UART_SCR 0 /* I/O: Scratch Register */
#define UART_EMSR 0 /* (LCR=BF) Extended Mode Select Register
* FCTR bit 6 selects SCR or EMSR
* XR16c85x only */
#else /* not CONFIG_SERIAL_M32R_PLDSIO */
#define SIOCR 0x000
#define SIOMOD0 0x004
#define SIOMOD1 0x008
#define SIOSTS 0x00c
#define SIOTRCR 0x010
#define SIOBAUR 0x014
#define SIORBAUR 0x018
#define SIOTXB 0x01c
#define SIORXB 0x020
#define UART_RX M32R_SIO0_RXB_PORTL /* In: Receive buffer (DLAB=0) */
#define UART_TX M32R_SIO0_TXB_PORTL /* Out: Transmit buffer (DLAB=0) */
#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx
* In: Fifo count
* Out: Fifo custom trigger levels
* XR16C85x only */
#define UART_DLM 0 /* Out: Divisor Latch High (DLAB=1) */
#define UART_IER M32R_SIO0_TRCR_PORTL /* Out: Interrupt Enable Register */
#define UART_FCTR 0 /* (LCR=BF) Feature Control Register
* XR16C85x only */
#define UART_IIR 0 /* In: Interrupt ID Register */
#define UART_FCR 0 /* Out: FIFO Control Register */
#define UART_EFR 0 /* I/O: Extended Features Register */
/* (DLAB=1, 16C660 only) */
#define UART_LCR 0 /* Out: Line Control Register */
#define UART_MCR 0 /* Out: Modem Control Register */
#define UART_LSR M32R_SIO0_STS_PORTL /* In: Line Status Register */
#define UART_MSR 0 /* In: Modem Status Register */
#define UART_SCR 0 /* I/O: Scratch Register */
#define UART_EMSR 0 /* (LCR=BF) Extended Mode Select Register
* FCTR bit 6 selects SCR or EMSR
* XR16c85x only */
#endif /* CONFIG_SERIAL_M32R_PLDSIO */
#define UART_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* These are the definitions for the FIFO Control Register
* (16650 only)
*/
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */
#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
/* 16650 redefinitions */
#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
/* TI 16750 definitions */
#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode */
/*
* These are the definitions for the Line Control Register
*
* Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
* UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
*/
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Parity Enable */
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
/*
* These are the definitions for the Line Status Register
*/
#define UART_LSR_TEMT 0x02 /* Transmitter empty */
#define UART_LSR_THRE 0x01 /* Transmit-hold-register empty */
#define UART_LSR_BI 0x00 /* Break interrupt indicator */
#define UART_LSR_FE 0x80 /* Frame error indicator */
#define UART_LSR_PE 0x40 /* Parity error indicator */
#define UART_LSR_OE 0x20 /* Overrun error indicator */
#define UART_LSR_DR 0x04 /* Receiver data ready */
/*
* These are the definitions for the Interrupt Identification Register
*/
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
/*
* These are the definitions for the Interrupt Enable Register
*/
#define UART_IER_MSI 0x00 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x08 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x03 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x04 /* Enable receiver data interrupt */
/*
* Sleep mode for ST16650 and TI16750.
* Note that for 16650, EFR-bit 4 must be selected as well.
*/
#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
/*
* These are the definitions for the Modem Control Register
*/
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR complement */
/*
* These are the definitions for the Modem Status Register
*/
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
#define UART_MSR_RI 0x40 /* Ring Indicator */
#define UART_MSR_DSR 0x20 /* Data Set Ready */
#define UART_MSR_CTS 0x10 /* Clear to Send */
#define UART_MSR_DDCD 0x08 /* Delta DCD */
#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
#define UART_MSR_DDSR 0x02 /* Delta DSR */
#define UART_MSR_DCTS 0x01 /* Delta CTS */
#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
/*
* These are the definitions for the Extended Features Register
* (StarTech 16C660 only, when DLAB=1)
*/
#define UART_EFR_CTS 0x80 /* CTS flow control */
#define UART_EFR_RTS 0x40 /* RTS flow control */
#define UART_EFR_SCD 0x20 /* Special character detect */
#define UART_EFR_ECB 0x10 /* Enhanced control bit */
/*
* the low four bits control software flow control
*/
/*
* These register definitions are for the 16C950
*/
#define UART_ASR 0x01 /* Additional Status Register */
#define UART_RFL 0x03 /* Receiver FIFO level */
#define UART_TFL 0x04 /* Transmitter FIFO level */
#define UART_ICR 0x05 /* Index Control Register */
/* The 16950 ICR registers */
#define UART_ACR 0x00 /* Additional Control Register */
#define UART_CPR 0x01 /* Clock Prescalar Register */
#define UART_TCR 0x02 /* Times Clock Register */
#define UART_CKS 0x03 /* Clock Select Register */
#define UART_TTL 0x04 /* Transmitter Interrupt Trigger Level */
#define UART_RTL 0x05 /* Receiver Interrupt Trigger Level */
#define UART_FCL 0x06 /* Flow Control Level Lower */
#define UART_FCH 0x07 /* Flow Control Level Higher */
#define UART_ID1 0x08 /* ID #1 */
#define UART_ID2 0x09 /* ID #2 */
#define UART_ID3 0x0A /* ID #3 */
#define UART_REV 0x0B /* Revision */
#define UART_CSR 0x0C /* Channel Software Reset */
#define UART_NMR 0x0D /* Nine-bit Mode Register */
#define UART_CTR 0xFF
/*
* The 16C950 Additional Control Reigster
*/
#define UART_ACR_RXDIS 0x01 /* Receiver disable */
#define UART_ACR_TXDIS 0x02 /* Receiver disable */
#define UART_ACR_DSRFC 0x04 /* DSR Flow Control */
#define UART_ACR_TLENB 0x20 /* 950 trigger levels enable */
#define UART_ACR_ICRRD 0x40 /* ICR Read enable */
#define UART_ACR_ASREN 0x80 /* Additional status enable */
/*
* These are the definitions for the Feature Control Register
* (XR16C85x only, when LCR=bf; doubles with the Interrupt Enable
* Register, UART register #1)
*/
#define UART_FCTR_RTS_NODELAY 0x00 /* RTS flow control delay */
#define UART_FCTR_RTS_4DELAY 0x01
#define UART_FCTR_RTS_6DELAY 0x02
#define UART_FCTR_RTS_8DELAY 0x03
#define UART_FCTR_IRDA 0x04 /* IrDa data encode select */
#define UART_FCTR_TX_INT 0x08 /* Tx interrupt type select */
#define UART_FCTR_TRGA 0x00 /* Tx/Rx 550 trigger table select */
#define UART_FCTR_TRGB 0x10 /* Tx/Rx 650 trigger table select */
#define UART_FCTR_TRGC 0x20 /* Tx/Rx 654 trigger table select */
#define UART_FCTR_TRGD 0x30 /* Tx/Rx 850 programmable trigger select */
#define UART_FCTR_SCR_SWAP 0x40 /* Scratch pad register swap */
#define UART_FCTR_RX 0x00 /* Programmable trigger mode select */
#define UART_FCTR_TX 0x80 /* Programmable trigger mode select */
/*
* These are the definitions for the Enhanced Mode Select Register
* (XR16C85x only, when LCR=bf and FCTR bit 6=1; doubles with the
* Scratch register, UART register #7)
*/
#define UART_EMSR_FIFO_COUNT 0x01 /* Rx/Tx select */
#define UART_EMSR_ALT_COUNT 0x02 /* Alternating count select */
/*
* These are the definitions for the Programmable Trigger
* Register (XR16C85x only, when LCR=bf; doubles with the UART RX/TX
* register, UART register #0)
*/
#define UART_TRG_1 0x01
#define UART_TRG_4 0x04
#define UART_TRG_8 0x08
#define UART_TRG_16 0x10
#define UART_TRG_32 0x20
#define UART_TRG_64 0x40
#define UART_TRG_96 0x60
#define UART_TRG_120 0x78
#define UART_TRG_128 0x80
/*
* These definitions are for the RSA-DV II/S card, from
*
* Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
*/
#define UART_RSA_BASE (-8)
#define UART_RSA_MSR ((UART_RSA_BASE) + 0) /* I/O: Mode Select Register */
#define UART_RSA_MSR_SWAP (1 << 0) /* Swap low/high 8 bytes in I/O port addr */
#define UART_RSA_MSR_FIFO (1 << 2) /* Enable the external FIFO */
#define UART_RSA_MSR_FLOW (1 << 3) /* Enable the auto RTS/CTS flow control */
#define UART_RSA_MSR_ITYP (1 << 4) /* Level (1) / Edge triger (0) */
#define UART_RSA_IER ((UART_RSA_BASE) + 1) /* I/O: Interrupt Enable Register */
#define UART_RSA_IER_Rx_FIFO_H (1 << 0) /* Enable Rx FIFO half full int. */
#define UART_RSA_IER_Tx_FIFO_H (1 << 1) /* Enable Tx FIFO half full int. */
#define UART_RSA_IER_Tx_FIFO_E (1 << 2) /* Enable Tx FIFO empty int. */
#define UART_RSA_IER_Rx_TOUT (1 << 3) /* Enable char receive timeout int */
#define UART_RSA_IER_TIMER (1 << 4) /* Enable timer interrupt */
#define UART_RSA_SRR ((UART_RSA_BASE) + 2) /* IN: Status Read Register */
#define UART_RSA_SRR_Tx_FIFO_NEMP (1 << 0) /* Tx FIFO is not empty (1) */
#define UART_RSA_SRR_Tx_FIFO_NHFL (1 << 1) /* Tx FIFO is not half full (1) */
#define UART_RSA_SRR_Tx_FIFO_NFUL (1 << 2) /* Tx FIFO is not full (1) */
#define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
#define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
#define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */
#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */
#define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
#define UART_RSA_TIVSR ((UART_RSA_BASE) + 3) /* I/O: Timer Interval Value Set Register */
#define UART_RSA_TCR ((UART_RSA_BASE) + 4) /* OUT: Timer Control Register */
#define UART_RSA_TCR_SWITCH (1 << 0) /* Timer on */
/*
* The RSA DSV/II board has two fixed clock frequencies. One is the
* standard rate, and the other is 8 times faster.
*/
#define SERIAL_RSA_BAUD_BASE (921600)
#define SERIAL_RSA_BAUD_BASE_LO (SERIAL_RSA_BAUD_BASE / 8)
#endif /* _M32R_SIO_REG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/*
* mcfserial.c -- serial driver for ColdFire internal UARTS.
*
* Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com>
* Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
* Copyright (c) 2002 SnapGear Inc., <www.snapgear.com>
*
* Based on code from 68332serial.c which was:
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1998 TSHG
* Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
*/
#ifndef _MCF_SERIAL_H
#define _MCF_SERIAL_H
#include <linux/config.h>
#include <linux/serial.h>
#ifdef __KERNEL__
/*
* Define a local serial stats structure.
*/
struct mcf_stats {
unsigned int rx;
unsigned int tx;
unsigned int rxbreak;
unsigned int rxframing;
unsigned int rxparity;
unsigned int rxoverrun;
};
/*
* This is our internal structure for each serial port's state.
* Each serial port has one of these structures associated with it.
*/
struct mcf_serial {
int magic;
volatile unsigned char *addr; /* UART memory address */
int irq;
int flags; /* defined in tty.h */
int type; /* UART type */
struct tty_struct *tty;
unsigned char imr; /* Software imr register */
unsigned int baud;
int sigs;
int custom_divisor;
int x_char; /* xon/xoff character */
int baud_base;
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
unsigned long event;
int line;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
struct mcf_stats stats;
struct work_struct tqueue;
struct work_struct tqueue_hangup;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
};
#endif /* __KERNEL__ */
#endif /* _MCF_SERIAL_H */

View File

@@ -0,0 +1,869 @@
/*
* drivers/serial/mpc52xx_uart.c
*
* Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
*
* FIXME According to the usermanual the status bits in the status register
* are only updated when the peripherals access the FIFO and not when the
* CPU access them. So since we use this bits to know when we stop writing
* and reading, they may not be updated in-time and a race condition may
* exists. But I haven't be able to prove this and I don't care. But if
* any problem arises, it might worth checking. The TX/RX FIFO Stats
* registers should be used in addition.
* Update: Actually, they seem updated ... At least the bits we use.
*
*
* Maintainer : Sylvain Munaut <tnt@246tNt.com>
*
* Some of the code has been inspired/copied from the 2.4 code written
* by Dale Farnsworth <dfarnsworth@mvista.com>.
*
* Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2003 MontaVista, Software, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
/* OCP Usage :
*
* This drivers uses the OCP model. To load the serial driver for one of the
* PSCs, just add this to the core_ocp table :
*
* {
* .vendor = OCP_VENDOR_FREESCALE,
* .function = OCP_FUNC_PSC_UART,
* .index = 0,
* .paddr = MPC52xx_PSC1,
* .irq = MPC52xx_PSC1_IRQ,
* .pm = OCP_CPM_NA,
* },
*
* This is for PSC1, replace the paddr and irq according to the PSC you want to
* use. The driver all necessary registers to place the PSC in uart mode without
* DCD. However, the pin multiplexing aren't changed and should be set either
* by the bootloader or in the platform init code.
* The index field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2,
* and so on). So the PSC1 is mapped to /dev/ttyS0, PSC2 to /dev/ttyS1 and so
* on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly for
* the console code : without this 1:1 mapping, at early boot time, when we are
* parsing the kernel args console=ttyS?, we wouldn't know wich PSC it will be
* mapped to because OCP stuff is not yet initialized.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/sysrq.h>
#include <linux/console.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/ocp.h>
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */
static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
/* Rem: - We use the read_status_mask as a shadow of
* psc->mpc52xx_psc_imr
* - It's important that is array is all zero on start as we
* use it to know if it's initialized or not ! If it's not sure
* it's cleared, then a memset(...,0,...) should be added to
* the console_init
*/
#define PSC(port) ((struct mpc52xx_psc *)((port)->membase))
/* Forward declaration of the interruption handling routine */
static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs);
/* Simple macro to test if a port is console or not. This one is taken
* for serial_core.c and maybe should be moved to serial_core.h ? */
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
#else
#define uart_console(port) (0)
#endif
/* ======================================================================== */
/* UART operations */
/* ======================================================================== */
static unsigned int
mpc52xx_uart_tx_empty(struct uart_port *port)
{
int status = in_be16(&PSC(port)->mpc52xx_psc_status);
return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
}
static void
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* Not implemented */
}
static unsigned int
mpc52xx_uart_get_mctrl(struct uart_port *port)
{
/* Not implemented */
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void
mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
/* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
static void
mpc52xx_uart_start_tx(struct uart_port *port, unsigned int tty_start)
{
/* port->lock taken by caller */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
static void
mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->x_char = ch;
if (ch) {
/* Make sure tx interrupts are on */
/* Truly necessary ??? They should be anyway */
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
spin_unlock_irqrestore(&port->lock, flags);
}
static void
mpc52xx_uart_stop_rx(struct uart_port *port)
{
/* port->lock taken by caller */
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
}
static void
mpc52xx_uart_enable_ms(struct uart_port *port)
{
/* Not implemented */
}
static void
mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if ( ctl == -1 )
out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);
else
out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);
spin_unlock_irqrestore(&port->lock, flags);
}
static int
mpc52xx_uart_startup(struct uart_port *port)
{
struct mpc52xx_psc *psc = PSC(port);
/* Reset/activate the port, clear and enable interrupts */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
out_8(&psc->command,MPC52xx_PSC_RST_TX);
out_be32(&psc->sicr,0); /* UART mode DCD ignored */
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
out_8(&psc->rfcntl, 0x00);
out_be16(&psc->rfalarm, 0x1ff);
out_8(&psc->tfcntl, 0x07);
out_be16(&psc->tfalarm, 0x80);
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
return 0;
}
static void
mpc52xx_uart_shutdown(struct uart_port *port)
{
struct mpc52xx_psc *psc = PSC(port);
/* Shut down the port, interrupt and all */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
out_8(&psc->command,MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
}
static void
mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
struct termios *old)
{
struct mpc52xx_psc *psc = PSC(port);
unsigned long flags;
unsigned char mr1, mr2;
unsigned short ctr;
unsigned int j, baud, quot;
/* Prepare what we're gonna write */
mr1 = 0;
switch (new->c_cflag & CSIZE) {
case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS;
break;
case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS;
break;
case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS;
break;
case CS8:
default: mr1 |= MPC52xx_PSC_MODE_8_BITS;
}
if (new->c_cflag & PARENB) {
mr1 |= (new->c_cflag & PARODD) ?
MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
} else
mr1 |= MPC52xx_PSC_MODE_PARNONE;
mr2 = 0;
if (new->c_cflag & CSTOPB)
mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
else
mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
MPC52xx_PSC_MODE_ONE_STOP;
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
ctr = quot & 0xffff;
/* Get the lock */
spin_lock_irqsave(&port->lock, flags);
/* Update the per-port timeout */
uart_update_timeout(port, new->c_cflag, baud);
/* Do our best to flush TX & RX, so we don't loose anything */
/* But we don't wait indefinitly ! */
j = 5000000; /* Maximum wait */
/* FIXME Can't receive chars since set_termios might be called at early
* boot for the console, all stuff is not yet ready to receive at that
* time and that just makes the kernel oops */
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
--j)
udelay(1);
if (!j)
printk( KERN_ERR "mpc52xx_uart.c: "
"Unable to flush RX & TX fifos in-time in set_termios."
"Some chars may have been lost.\n" );
/* Reset the TX & RX */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
out_8(&psc->command,MPC52xx_PSC_RST_TX);
/* Send new mode settings */
out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&psc->mode,mr1);
out_8(&psc->mode,mr2);
out_8(&psc->ctur,ctr >> 8);
out_8(&psc->ctlr,ctr & 0xff);
/* Reenable TX & RX */
out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
/* We're all set, release the lock */
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *
mpc52xx_uart_type(struct uart_port *port)
{
return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
}
static void
mpc52xx_uart_release_port(struct uart_port *port)
{
if (port->flags & UPF_IOREMAP) { /* remapped by us ? */
iounmap(port->membase);
port->membase = NULL;
}
}
static int
mpc52xx_uart_request_port(struct uart_port *port)
{
if (port->flags & UPF_IOREMAP) /* Need to remap ? */
port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));
return port->membase != NULL ? 0 : -EBUSY;
}
static void
mpc52xx_uart_config_port(struct uart_port *port, int flags)
{
if ( (flags & UART_CONFIG_TYPE) &&
(mpc52xx_uart_request_port(port) == 0) )
port->type = PORT_MPC52xx;
}
static int
mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if ( ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx )
return -EINVAL;
if ( (ser->irq != port->irq) ||
(ser->io_type != SERIAL_IO_MEM) ||
(ser->baud_base != port->uartclk) ||
// FIXME Should check addresses/irq as well ?
(ser->hub6 != 0 ) )
return -EINVAL;
return 0;
}
static struct uart_ops mpc52xx_uart_ops = {
.tx_empty = mpc52xx_uart_tx_empty,
.set_mctrl = mpc52xx_uart_set_mctrl,
.get_mctrl = mpc52xx_uart_get_mctrl,
.stop_tx = mpc52xx_uart_stop_tx,
.start_tx = mpc52xx_uart_start_tx,
.send_xchar = mpc52xx_uart_send_xchar,
.stop_rx = mpc52xx_uart_stop_rx,
.enable_ms = mpc52xx_uart_enable_ms,
.break_ctl = mpc52xx_uart_break_ctl,
.startup = mpc52xx_uart_startup,
.shutdown = mpc52xx_uart_shutdown,
.set_termios = mpc52xx_uart_set_termios,
/* .pm = mpc52xx_uart_pm, Not supported yet */
/* .set_wake = mpc52xx_uart_set_wake, Not supported yet */
.type = mpc52xx_uart_type,
.release_port = mpc52xx_uart_release_port,
.request_port = mpc52xx_uart_request_port,
.config_port = mpc52xx_uart_config_port,
.verify_port = mpc52xx_uart_verify_port
};
/* ======================================================================== */
/* Interrupt handling */
/* ======================================================================== */
static inline int
mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
{
struct tty_struct *tty = port->info->tty;
unsigned char ch;
unsigned short status;
/* While we can read, do so ! */
while ( (status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
MPC52xx_PSC_SR_RXRDY) {
/* If we are full, just stop reading */
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break;
/* Get the char */
ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
/* Handle sysreq char */
#ifdef SUPPORT_SYSRQ
if (uart_handle_sysrq_char(port, ch, regs)) {
port->sysrq = 0;
continue;
}
#endif
/* Store it */
*tty->flip.char_buf_ptr = ch;
*tty->flip.flag_buf_ptr = 0;
port->icount.rx++;
if ( status & (MPC52xx_PSC_SR_PE |
MPC52xx_PSC_SR_FE |
MPC52xx_PSC_SR_RB |
MPC52xx_PSC_SR_OE) ) {
if (status & MPC52xx_PSC_SR_RB) {
*tty->flip.flag_buf_ptr = TTY_BREAK;
uart_handle_break(port);
} else if (status & MPC52xx_PSC_SR_PE)
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (status & MPC52xx_PSC_SR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
if (status & MPC52xx_PSC_SR_OE) {
/*
* Overrun is special, since it's
* reported immediately, and doesn't
* affect the current character
*/
if (tty->flip.count < (TTY_FLIPBUF_SIZE-1)) {
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
}
*tty->flip.flag_buf_ptr = TTY_OVERRUN;
}
/* Clear error condition */
out_8(&PSC(port)->command,MPC52xx_PSC_RST_ERR_STAT);
}
tty->flip.char_buf_ptr++;
tty->flip.flag_buf_ptr++;
tty->flip.count++;
}
tty_flip_buffer_push(tty);
return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
}
static inline int
mpc52xx_uart_int_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
/* Process out of band chars */
if (port->x_char) {
out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char);
port->icount.tx++;
port->x_char = 0;
return 1;
}
/* Nothing to do ? */
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
mpc52xx_uart_stop_tx(port,0);
return 0;
}
/* Send chars */
while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) {
out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
}
/* Wake up */
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
/* Maybe we're done after all */
if (uart_circ_empty(xmit)) {
mpc52xx_uart_stop_tx(port,0);
return 0;
}
return 1;
}
static irqreturn_t
mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = (struct uart_port *) dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
unsigned short status;
if ( irq != port->irq ) {
printk( KERN_WARNING
"mpc52xx_uart_int : " \
"Received wrong int %d. Waiting for %d\n",
irq, port->irq);
return IRQ_NONE;
}
spin_lock(&port->lock);
/* While we have stuff to do, we continue */
do {
/* If we don't find anything to do, we stop */
keepgoing = 0;
/* Read status */
status = in_be16(&PSC(port)->mpc52xx_psc_isr);
status &= port->read_status_mask;
/* Do we need to receive chars ? */
/* For this RX interrupts must be on and some chars waiting */
if ( status & MPC52xx_PSC_IMR_RXRDY )
keepgoing |= mpc52xx_uart_int_rx_chars(port, regs);
/* Do we need to send chars ? */
/* For this, TX must be ready and TX interrupt enabled */
if ( status & MPC52xx_PSC_IMR_TXRDY )
keepgoing |= mpc52xx_uart_int_tx_chars(port);
/* Limit number of iteration */
if ( !(--pass) )
keepgoing = 0;
} while (keepgoing);
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
/* ======================================================================== */
/* Console ( if applicable ) */
/* ======================================================================== */
#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE
static void __init
mpc52xx_console_get_options(struct uart_port *port,
int *baud, int *parity, int *bits, int *flow)
{
struct mpc52xx_psc *psc = PSC(port);
unsigned char mr1;
/* Read the mode registers */
out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
mr1 = in_8(&psc->mode);
/* CT{U,L}R are write-only ! */
*baud = __res.bi_baudrate ?
__res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
/* Parse them */
switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
case MPC52xx_PSC_MODE_5_BITS: *bits = 5; break;
case MPC52xx_PSC_MODE_6_BITS: *bits = 6; break;
case MPC52xx_PSC_MODE_7_BITS: *bits = 7; break;
case MPC52xx_PSC_MODE_8_BITS:
default: *bits = 8;
}
if (mr1 & MPC52xx_PSC_MODE_PARNONE)
*parity = 'n';
else
*parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
}
static void
mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_port *port = &mpc52xx_uart_ports[co->index];
struct mpc52xx_psc *psc = PSC(port);
unsigned int i, j;
/* Disable interrupts */
out_be16(&psc->mpc52xx_psc_imr, 0);
/* Wait the TX buffer to be empty */
j = 5000000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
--j)
udelay(1);
/* Write all the chars */
for ( i=0 ; i<count ; i++ ) {
/* Send the char */
out_8(&psc->mpc52xx_psc_buffer_8, *s);
/* Line return handling */
if ( *s++ == '\n' )
out_8(&psc->mpc52xx_psc_buffer_8, '\r');
/* Wait the TX buffer to be empty */
j = 20000; /* Maximum wait */
while (!(in_be16(&psc->mpc52xx_psc_status) &
MPC52xx_PSC_SR_TXEMP) && --j)
udelay(1);
}
/* Restore interrupt state */
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
static int __init
mpc52xx_console_setup(struct console *co, char *options)
{
struct uart_port *port = &mpc52xx_uart_ports[co->index];
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
/* Basic port init. Needed since we use some uart_??? func before
* real init for early access */
port->lock = SPIN_LOCK_UNLOCKED;
port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
port->ops = &mpc52xx_uart_ops;
port->mapbase = MPC52xx_PSCx(co->index);
/* We ioremap ourself */
port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));
if (port->membase == NULL) {
release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
return -EBUSY;
}
/* Setup the port parameters accoding to options */
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
extern struct uart_driver mpc52xx_uart_driver;
static struct console mpc52xx_console = {
.name = "ttyS",
.write = mpc52xx_console_write,
.device = uart_console_device,
.setup = mpc52xx_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1, /* Specified on the cmdline (e.g. console=ttyS0 ) */
.data = &mpc52xx_uart_driver,
};
static int __init
mpc52xx_console_init(void)
{
register_console(&mpc52xx_console);
return 0;
}
console_initcall(mpc52xx_console_init);
#define MPC52xx_PSC_CONSOLE &mpc52xx_console
#else
#define MPC52xx_PSC_CONSOLE NULL
#endif
/* ======================================================================== */
/* UART Driver */
/* ======================================================================== */
static struct uart_driver mpc52xx_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "mpc52xx_psc_uart",
.dev_name = "ttyS",
.devfs_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = MPC52xx_PSC_MAXNUM,
.cons = MPC52xx_PSC_CONSOLE,
};
/* ======================================================================== */
/* OCP Driver */
/* ======================================================================== */
static int __devinit
mpc52xx_uart_probe(struct ocp_device *ocp)
{
struct uart_port *port = NULL;
int idx, ret;
/* Get the corresponding port struct */
idx = ocp->def->index;
if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
port = &mpc52xx_uart_ports[idx];
/* Init the port structure */
port->lock = SPIN_LOCK_UNLOCKED;
port->mapbase = ocp->def->paddr;
port->irq = ocp->def->irq;
port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
port->fifosize = 255; /* Should be 512 ! But it can't be */
/* stored in a unsigned char */
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF |
( uart_console(port) ? 0 : UPF_IOREMAP );
port->line = idx;
port->ops = &mpc52xx_uart_ops;
port->read_status_mask = 0;
/* Requests the mem & irqs */
/* Unlike other serial drivers, we reserve the resources here, so we
* can detect early if multiple drivers uses the same PSC. Special
* care must be taken with the console PSC
*/
ret = request_irq(
port->irq, mpc52xx_uart_int,
SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
if (ret)
goto error;
ret = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
if (ret)
goto free_irq;
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
if (ret)
goto release_mem;
ocp_set_drvdata(ocp, (void*)port);
return 0;
free_irq:
free_irq(port->irq, mpc52xx_uart_int);
release_mem:
release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
error:
if (uart_console(port))
printk( "mpc52xx_uart.c: Error during resource alloction for "
"the console port !!! Check that the console PSC is "
"not used by another OCP driver !!!\n" );
return ret;
}
static void
mpc52xx_uart_remove(struct ocp_device *ocp)
{
struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
ocp_set_drvdata(ocp, NULL);
if (port) {
uart_remove_one_port(&mpc52xx_uart_driver, port);
release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
free_irq(port->irq, mpc52xx_uart_int);
}
}
#ifdef CONFIG_PM
static int
mpc52xx_uart_suspend(struct ocp_device *ocp, u32 state)
{
struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
uart_suspend_port(&mpc52xx_uart_driver, port);
return 0;
}
static int
mpc52xx_uart_resume(struct ocp_device *ocp)
{
struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp);
uart_resume_port(&mpc52xx_uart_driver, port);
return 0;
}
#endif
static struct ocp_device_id mpc52xx_uart_ids[] __devinitdata = {
{ .vendor = OCP_VENDOR_FREESCALE, .function = OCP_FUNC_PSC_UART },
{ .vendor = OCP_VENDOR_INVALID /* Terminating entry */ }
};
MODULE_DEVICE_TABLE(ocp, mpc52xx_uart_ids);
static struct ocp_driver mpc52xx_uart_ocp_driver = {
.name = "mpc52xx_psc_uart",
.id_table = mpc52xx_uart_ids,
.probe = mpc52xx_uart_probe,
.remove = mpc52xx_uart_remove,
#ifdef CONFIG_PM
.suspend = mpc52xx_uart_suspend,
.resume = mpc52xx_uart_resume,
#endif
};
/* ======================================================================== */
/* Module */
/* ======================================================================== */
static int __init
mpc52xx_uart_init(void)
{
int ret;
printk(KERN_INFO "Serial: MPC52xx PSC driver\n");
ret = uart_register_driver(&mpc52xx_uart_driver);
if (ret)
return ret;
ret = ocp_register_driver(&mpc52xx_uart_ocp_driver);
return ret;
}
static void __exit
mpc52xx_uart_exit(void)
{
ocp_unregister_driver(&mpc52xx_uart_ocp_driver);
uart_unregister_driver(&mpc52xx_uart_driver);
}
module_init(mpc52xx_uart_init);
module_exit(mpc52xx_uart_exit);
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
MODULE_DESCRIPTION("Freescale MPC52xx PSC UART");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,539 @@
/*
** mux.c:
** serial driver for the Mux console found in some PA-RISC servers.
**
** (c) Copyright 2002 Ryan Bradetich
** (c) Copyright 2002 Hewlett-Packard Company
**
** 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 Driver currently only supports the console (port 0) on the MUX.
** Additional work will be needed on this driver to enable the full
** functionality of the MUX.
**
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/slab.h>
#include <linux/delay.h> /* for udelay */
#include <linux/device.h>
#include <asm/io.h>
#include <asm/parisc-device.h>
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#define MUX_OFFSET 0x800
#define MUX_LINE_OFFSET 0x80
#define MUX_FIFO_SIZE 255
#define MUX_POLL_DELAY (30 * HZ / 1000)
#define IO_DATA_REG_OFFSET 0x3c
#define IO_DCOUNT_REG_OFFSET 0x40
#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
#define MUX_NR 256
static unsigned int port_cnt = 0;
static struct uart_port mux_ports[MUX_NR];
static struct uart_driver mux_driver = {
.owner = THIS_MODULE,
.driver_name = "ttyB",
.dev_name = "ttyB",
.major = MUX_MAJOR,
.minor = 0,
.nr = MUX_NR,
};
static struct timer_list mux_timer;
#define UART_PUT_CHAR(p, c) __raw_writel((c), (unsigned long)(p)->membase + IO_DATA_REG_OFFSET)
#define UART_GET_FIFO_CNT(p) __raw_readl((unsigned long)(p)->membase + IO_DCOUNT_REG_OFFSET)
#define GET_MUX_PORTS(iodc_data) ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8
/**
* mux_tx_empty - Check if the transmitter fifo is empty.
* @port: Ptr to the uart_port.
*
* This function test if the transmitter fifo for the port
* described by 'port' is empty. If it is empty, this function
* should return TIOCSER_TEMT, otherwise return 0.
*/
static unsigned int mux_tx_empty(struct uart_port *port)
{
unsigned int cnt = __raw_readl((unsigned long)port->membase
+ IO_DCOUNT_REG_OFFSET);
return cnt ? 0 : TIOCSER_TEMT;
}
/**
* mux_set_mctrl - Set the current state of the modem control inputs.
* @ports: Ptr to the uart_port.
* @mctrl: Modem control bits.
*
* The Serial MUX does not support CTS, DCD or DSR so this function
* is ignored.
*/
static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
/**
* mux_get_mctrl - Returns the current state of modem control inputs.
* @port: Ptr to the uart_port.
*
* The Serial MUX does not support CTS, DCD or DSR so these lines are
* treated as permanently active.
*/
static unsigned int mux_get_mctrl(struct uart_port *port)
{
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
/**
* mux_stop_tx - Stop transmitting characters.
* @port: Ptr to the uart_port.
* @tty_stop: tty layer issue this command?
*
* The Serial MUX does not support this function.
*/
static void mux_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
}
/**
* mux_start_tx - Start transmitting characters.
* @port: Ptr to the uart_port.
* @tty_start: tty layer issue this command?
*
* The Serial Mux does not support this function.
*/
static void mux_start_tx(struct uart_port *port, unsigned int tty_start)
{
}
/**
* mux_stop_rx - Stop receiving characters.
* @port: Ptr to the uart_port.
*
* The Serial Mux does not support this function.
*/
static void mux_stop_rx(struct uart_port *port)
{
}
/**
* mux_enable_ms - Enable modum status interrupts.
* @port: Ptr to the uart_port.
*
* The Serial Mux does not support this function.
*/
static void mux_enable_ms(struct uart_port *port)
{
}
/**
* mux_break_ctl - Control the transmitssion of a break signal.
* @port: Ptr to the uart_port.
* @break_state: Raise/Lower the break signal.
*
* The Serial Mux does not support this function.
*/
static void mux_break_ctl(struct uart_port *port, int break_state)
{
}
/**
* mux_write - Write chars to the mux fifo.
* @port: Ptr to the uart_port.
*
* This function writes all the data from the uart buffer to
* the mux fifo.
*/
static void mux_write(struct uart_port *port)
{
int count;
struct circ_buf *xmit = &port->info->xmit;
if(port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
mux_stop_tx(port, 0);
return;
}
count = (port->fifosize) - UART_GET_FIFO_CNT(port);
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if(uart_circ_empty(xmit))
break;
} while(--count > 0);
while(UART_GET_FIFO_CNT(port))
udelay(1);
if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
mux_stop_tx(port, 0);
}
/**
* mux_read - Read chars from the mux fifo.
* @port: Ptr to the uart_port.
*
* This reads all available data from the mux's fifo and pushes
* the data to the tty layer.
*/
static void mux_read(struct uart_port *port)
{
int data;
struct tty_struct *tty = port->info->tty;
__u32 start_count = port->icount.rx;
while(1) {
data = __raw_readl((unsigned long)port->membase
+ IO_DATA_REG_OFFSET);
if (MUX_STATUS(data))
continue;
if (MUX_EOFIFO(data))
break;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
continue;
*tty->flip.char_buf_ptr = data & 0xffu;
*tty->flip.flag_buf_ptr = TTY_NORMAL;
port->icount.rx++;
if (MUX_BREAK(data)) {
port->icount.brk++;
if(uart_handle_break(port))
continue;
}
if (uart_handle_sysrq_char(port, data & 0xffu, NULL))
continue;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
}
if (start_count != port->icount.rx) {
tty_flip_buffer_push(tty);
}
}
/**
* mux_startup - Initialize the port.
* @port: Ptr to the uart_port.
*
* Grab any resources needed for this port and start the
* mux timer.
*/
static int mux_startup(struct uart_port *port)
{
mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
return 0;
}
/**
* mux_shutdown - Disable the port.
* @port: Ptr to the uart_port.
*
* Release any resources needed for the port.
*/
static void mux_shutdown(struct uart_port *port)
{
}
/**
* mux_set_termios - Chane port parameters.
* @port: Ptr to the uart_port.
* @termios: new termios settings.
* @old: old termios settings.
*
* The Serial Mux does not support this function.
*/
static void
mux_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
}
/**
* mux_type - Describe the port.
* @port: Ptr to the uart_port.
*
* Return a pointer to a string constant describing the
* specified port.
*/
static const char *mux_type(struct uart_port *port)
{
return "Mux";
}
/**
* mux_release_port - Release memory and IO regions.
* @port: Ptr to the uart_port.
*
* Release any memory and IO region resources currently in use by
* the port.
*/
static void mux_release_port(struct uart_port *port)
{
}
/**
* mux_request_port - Request memory and IO regions.
* @port: Ptr to the uart_port.
*
* Request any memory and IO region resources required by the port.
* If any fail, no resources should be registered when this function
* returns, and it should return -EBUSY on failure.
*/
static int mux_request_port(struct uart_port *port)
{
return 0;
}
/**
* mux_config_port - Perform port autoconfiguration.
* @port: Ptr to the uart_port.
* @type: Bitmask of required configurations.
*
* Perform any autoconfiguration steps for the port. This functino is
* called if the UPF_BOOT_AUTOCONF flag is specified for the port.
* [Note: This is required for now because of a bug in the Serial core.
* rmk has already submitted a patch to linus, should be available for
* 2.5.47.]
*/
static void mux_config_port(struct uart_port *port, int type)
{
port->type = PORT_MUX;
}
/**
* mux_verify_port - Verify the port information.
* @port: Ptr to the uart_port.
* @ser: Ptr to the serial information.
*
* Verify the new serial port information contained within serinfo is
* suitable for this port type.
*/
static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if(port->membase == NULL)
return -EINVAL;
return 0;
}
/**
* mux_drv_poll - Mux poll function.
* @unused: Unused variable
*
* This function periodically polls the Serial MUX to check for new data.
*/
static void mux_poll(unsigned long unused)
{
int i;
for(i = 0; i < port_cnt; ++i) {
if(!mux_ports[i].info)
continue;
mux_read(&mux_ports[i]);
mux_write(&mux_ports[i]);
}
mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
}
#ifdef CONFIG_SERIAL_MUX_CONSOLE
static void mux_console_write(struct console *co, const char *s, unsigned count)
{
while(count--)
pdc_iodc_putc(*s++);
}
static int mux_console_setup(struct console *co, char *options)
{
return 0;
}
struct tty_driver *mux_console_device(struct console *co, int *index)
{
*index = co->index;
return mux_driver.tty_driver;
}
static struct console mux_console = {
.name = "ttyB",
.write = mux_console_write,
.device = mux_console_device,
.setup = mux_console_setup,
.flags = CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
.index = 0,
};
#define MUX_CONSOLE &mux_console
#else
#define MUX_CONSOLE NULL
#endif
static struct uart_ops mux_pops = {
.tx_empty = mux_tx_empty,
.set_mctrl = mux_set_mctrl,
.get_mctrl = mux_get_mctrl,
.stop_tx = mux_stop_tx,
.start_tx = mux_start_tx,
.stop_rx = mux_stop_rx,
.enable_ms = mux_enable_ms,
.break_ctl = mux_break_ctl,
.startup = mux_startup,
.shutdown = mux_shutdown,
.set_termios = mux_set_termios,
.type = mux_type,
.release_port = mux_release_port,
.request_port = mux_request_port,
.config_port = mux_config_port,
.verify_port = mux_verify_port,
};
/**
* mux_probe - Determine if the Serial Mux should claim this device.
* @dev: The parisc device.
*
* Deterimine if the Serial Mux should claim this chip (return 0)
* or not (return 1).
*/
static int __init mux_probe(struct parisc_device *dev)
{
int i, status, ports;
u8 iodc_data[32];
unsigned long bytecnt;
struct uart_port *port;
status = pdc_iodc_read(&bytecnt, dev->hpa, 0, iodc_data, 32);
if(status != PDC_OK) {
printk(KERN_ERR "Serial mux: Unable to read IODC.\n");
return 1;
}
ports = GET_MUX_PORTS(iodc_data);
printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports);
if(!port_cnt) {
mux_driver.cons = MUX_CONSOLE;
status = uart_register_driver(&mux_driver);
if(status) {
printk(KERN_ERR "Serial mux: Unable to register driver.\n");
return 1;
}
init_timer(&mux_timer);
mux_timer.function = mux_poll;
}
for(i = 0; i < ports; ++i, ++port_cnt) {
port = &mux_ports[port_cnt];
port->iobase = 0;
port->mapbase = dev->hpa + MUX_OFFSET + (i * MUX_LINE_OFFSET);
port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET);
port->iotype = SERIAL_IO_MEM;
port->type = PORT_MUX;
port->irq = SERIAL_IRQ_NONE;
port->uartclk = 0;
port->fifosize = MUX_FIFO_SIZE;
port->ops = &mux_pops;
port->flags = UPF_BOOT_AUTOCONF;
port->line = port_cnt;
status = uart_add_one_port(&mux_driver, port);
BUG_ON(status);
}
#ifdef CONFIG_SERIAL_MUX_CONSOLE
register_console(&mux_console);
#endif
return 0;
}
static struct parisc_device_id mux_tbl[] = {
{ HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
{ 0, }
};
MODULE_DEVICE_TABLE(parisc, mux_tbl);
static struct parisc_driver serial_mux_driver = {
.name = "Serial MUX",
.id_table = mux_tbl,
.probe = mux_probe,
};
/**
* mux_init - Serial MUX initalization procedure.
*
* Register the Serial MUX driver.
*/
static int __init mux_init(void)
{
return register_parisc_driver(&serial_mux_driver);
}
/**
* mux_exit - Serial MUX cleanup procedure.
*
* Unregister the Serial MUX driver from the tty layer.
*/
static void __exit mux_exit(void)
{
int i;
for (i = 0; i < port_cnt; i++) {
uart_remove_one_port(&mux_driver, &mux_ports[i]);
}
uart_unregister_driver(&mux_driver);
}
module_init(mux_init);
module_exit(mux_exit);
MODULE_AUTHOR("Ryan Bradetich");
MODULE_DESCRIPTION("Serial MUX driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,382 @@
#ifndef __PMAC_ZILOG_H__
#define __PMAC_ZILOG_H__
#define pmz_debug(fmt,arg...) dev_dbg(&uap->dev->ofdev.dev, fmt, ## arg)
/*
* At most 2 ESCCs with 2 ports each
*/
#define MAX_ZS_PORTS 4
/*
* We wrap our port structure around the generic uart_port.
*/
#define NUM_ZSREGS 17
struct uart_pmac_port {
struct uart_port port;
struct uart_pmac_port *mate;
/* macio_dev for the escc holding this port (maybe be null on
* early inited port)
*/
struct macio_dev *dev;
/* device node to this port, this points to one of 2 childs
* of "escc" node (ie. ch-a or ch-b)
*/
struct device_node *node;
/* Port type as obtained from device tree (IRDA, modem, ...) */
int port_type;
u8 curregs[NUM_ZSREGS];
unsigned int flags;
#define PMACZILOG_FLAG_IS_CONS 0x00000001
#define PMACZILOG_FLAG_IS_KGDB 0x00000002
#define PMACZILOG_FLAG_MODEM_STATUS 0x00000004
#define PMACZILOG_FLAG_IS_CHANNEL_A 0x00000008
#define PMACZILOG_FLAG_REGS_HELD 0x00000010
#define PMACZILOG_FLAG_TX_STOPPED 0x00000020
#define PMACZILOG_FLAG_TX_ACTIVE 0x00000040
#define PMACZILOG_FLAG_ENABLED 0x00000080
#define PMACZILOG_FLAG_IS_IRDA 0x00000100
#define PMACZILOG_FLAG_IS_INTMODEM 0x00000200
#define PMACZILOG_FLAG_HAS_DMA 0x00000400
#define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800
#define PMACZILOG_FLAG_IS_ASLEEP 0x00001000
#define PMACZILOG_FLAG_IS_OPEN 0x00002000
#define PMACZILOG_FLAG_IS_IRQ_ON 0x00004000
#define PMACZILOG_FLAG_IS_EXTCLK 0x00008000
#define PMACZILOG_FLAG_BREAK 0x00010000
unsigned char parity_mask;
unsigned char prev_status;
volatile u8 __iomem *control_reg;
volatile u8 __iomem *data_reg;
unsigned int tx_dma_irq;
unsigned int rx_dma_irq;
volatile struct dbdma_regs __iomem *tx_dma_regs;
volatile struct dbdma_regs __iomem *rx_dma_regs;
struct termios termios_cache;
};
#define to_pmz(p) ((struct uart_pmac_port *)(p))
static inline struct uart_pmac_port *pmz_get_port_A(struct uart_pmac_port *uap)
{
if (uap->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
return uap;
return uap->mate;
}
/*
* Register acessors. Note that we don't need to enforce a recovery
* delay on PCI PowerMac hardware, it's dealt in HW by the MacIO chip,
* though if we try to use this driver on older machines, we might have
* to add it back
*/
static inline u8 read_zsreg(struct uart_pmac_port *port, u8 reg)
{
if (reg != 0)
writeb(reg, port->control_reg);
return readb(port->control_reg);
}
static inline void write_zsreg(struct uart_pmac_port *port, u8 reg, u8 value)
{
if (reg != 0)
writeb(reg, port->control_reg);
writeb(value, port->control_reg);
}
static inline u8 read_zsdata(struct uart_pmac_port *port)
{
return readb(port->data_reg);
}
static inline void write_zsdata(struct uart_pmac_port *port, u8 data)
{
writeb(data, port->data_reg);
}
static inline void zssync(struct uart_pmac_port *port)
{
(void)readb(port->control_reg);
}
/* Conversion routines to/from brg time constants from/to bits
* per second.
*/
#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
/* The Zilog register set */
#define FLAG 0x7e
/* Write Register 0 */
#define R0 0 /* Register selects */
#define R1 1
#define R2 2
#define R3 3
#define R4 4
#define R5 5
#define R6 6
#define R7 7
#define R8 8
#define R9 9
#define R10 10
#define R11 11
#define R12 12
#define R13 13
#define R14 14
#define R15 15
#define R7P 16
#define NULLCODE 0 /* Null Code */
#define POINT_HIGH 0x8 /* Select upper half of registers */
#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
#define SEND_ABORT 0x18 /* HDLC Abort */
#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
#define RES_Tx_P 0x28 /* Reset TxINT Pending */
#define ERR_RES 0x30 /* Error Reset */
#define RES_H_IUS 0x38 /* Reset highest IUS */
#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
#define RES_EOM_L 0xC0 /* Reset EOM latch */
/* Write Register 1 */
#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
#define TxINT_ENAB 0x2 /* Tx Int Enable */
#define PAR_SPEC 0x4 /* Parity is special condition */
#define RxINT_DISAB 0 /* Rx Int Disable */
#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
#define INT_ERR_Rx 0x18 /* Int on error only */
#define RxINT_MASK 0x18
#define WT_RDY_RT 0x20 /* W/Req reflects recv if 1, xmit if 0 */
#define WT_FN_RDYFN 0x40 /* W/Req pin is DMA request if 1, wait if 0 */
#define WT_RDY_ENAB 0x80 /* Enable W/Req pin */
/* Write Register #2 (Interrupt Vector) */
/* Write Register 3 */
#define RxENABLE 0x1 /* Rx Enable */
#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
#define ENT_HM 0x10 /* Enter Hunt Mode */
#define AUTO_ENAB 0x20 /* Auto Enables */
#define Rx5 0x0 /* Rx 5 Bits/Character */
#define Rx7 0x40 /* Rx 7 Bits/Character */
#define Rx6 0x80 /* Rx 6 Bits/Character */
#define Rx8 0xc0 /* Rx 8 Bits/Character */
#define RxN_MASK 0xc0
/* Write Register 4 */
#define PAR_ENAB 0x1 /* Parity Enable */
#define PAR_EVEN 0x2 /* Parity Even/Odd* */
#define SYNC_ENAB 0 /* Sync Modes Enable */
#define SB1 0x4 /* 1 stop bit/char */
#define SB15 0x8 /* 1.5 stop bits/char */
#define SB2 0xc /* 2 stop bits/char */
#define SB_MASK 0xc
#define MONSYNC 0 /* 8 Bit Sync character */
#define BISYNC 0x10 /* 16 bit sync character */
#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
#define EXTSYNC 0x30 /* External Sync Mode */
#define X1CLK 0x0 /* x1 clock mode */
#define X16CLK 0x40 /* x16 clock mode */
#define X32CLK 0x80 /* x32 clock mode */
#define X64CLK 0xC0 /* x64 clock mode */
#define XCLK_MASK 0xC0
/* Write Register 5 */
#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
#define RTS 0x2 /* RTS */
#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
#define TxENABLE 0x8 /* Tx Enable */
#define SND_BRK 0x10 /* Send Break */
#define Tx5 0x0 /* Tx 5 bits (or less)/character */
#define Tx7 0x20 /* Tx 7 bits/character */
#define Tx6 0x40 /* Tx 6 bits/character */
#define Tx8 0x60 /* Tx 8 bits/character */
#define TxN_MASK 0x60
#define DTR 0x80 /* DTR */
/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
/* Write Register 7' (Some enhanced feature control) */
#define ENEXREAD 0x40 /* Enable read of some write registers */
/* Write Register 8 (transmit buffer) */
/* Write Register 9 (Master interrupt control) */
#define VIS 1 /* Vector Includes Status */
#define NV 2 /* No Vector */
#define DLC 4 /* Disable Lower Chain */
#define MIE 8 /* Master Interrupt Enable */
#define STATHI 0x10 /* Status high */
#define NORESET 0 /* No reset on write to R9 */
#define CHRB 0x40 /* Reset channel B */
#define CHRA 0x80 /* Reset channel A */
#define FHWRES 0xc0 /* Force hardware reset */
/* Write Register 10 (misc control bits) */
#define BIT6 1 /* 6 bit/8bit sync */
#define LOOPMODE 2 /* SDLC Loop mode */
#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
#define MARKIDLE 8 /* Mark/flag on idle */
#define GAOP 0x10 /* Go active on poll */
#define NRZ 0 /* NRZ mode */
#define NRZI 0x20 /* NRZI mode */
#define FM1 0x40 /* FM1 (transition = 1) */
#define FM0 0x60 /* FM0 (transition = 0) */
#define CRCPS 0x80 /* CRC Preset I/O */
/* Write Register 11 (Clock Mode control) */
#define TRxCXT 0 /* TRxC = Xtal output */
#define TRxCTC 1 /* TRxC = Transmit clock */
#define TRxCBR 2 /* TRxC = BR Generator Output */
#define TRxCDP 3 /* TRxC = DPLL output */
#define TRxCOI 4 /* TRxC O/I */
#define TCRTxCP 0 /* Transmit clock = RTxC pin */
#define TCTRxCP 8 /* Transmit clock = TRxC pin */
#define TCBR 0x10 /* Transmit clock = BR Generator output */
#define TCDPLL 0x18 /* Transmit clock = DPLL output */
#define RCRTxCP 0 /* Receive clock = RTxC pin */
#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
#define RCBR 0x40 /* Receive clock = BR Generator output */
#define RCDPLL 0x60 /* Receive clock = DPLL output */
#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
/* Write Register 12 (lower byte of baud rate generator time constant) */
/* Write Register 13 (upper byte of baud rate generator time constant) */
/* Write Register 14 (Misc control bits) */
#define BRENAB 1 /* Baud rate generator enable */
#define BRSRC 2 /* Baud rate generator source */
#define DTRREQ 4 /* DTR/Request function */
#define AUTOECHO 8 /* Auto Echo */
#define LOOPBAK 0x10 /* Local loopback */
#define SEARCH 0x20 /* Enter search mode */
#define RMC 0x40 /* Reset missing clock */
#define DISDPLL 0x60 /* Disable DPLL */
#define SSBR 0x80 /* Set DPLL source = BR generator */
#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
#define SFMM 0xc0 /* Set FM mode */
#define SNRZI 0xe0 /* Set NRZI mode */
/* Write Register 15 (external/status interrupt control) */
#define EN85C30 1 /* Enable some 85c30-enhanced registers */
#define ZCIE 2 /* Zero count IE */
#define ENSTFIFO 4 /* Enable status FIFO (SDLC) */
#define DCDIE 8 /* DCD IE */
#define SYNCIE 0x10 /* Sync/hunt IE */
#define CTSIE 0x20 /* CTS IE */
#define TxUIE 0x40 /* Tx Underrun/EOM IE */
#define BRKIE 0x80 /* Break/Abort IE */
/* Read Register 0 */
#define Rx_CH_AV 0x1 /* Rx Character Available */
#define ZCOUNT 0x2 /* Zero count */
#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
#define DCD 0x8 /* DCD */
#define SYNC_HUNT 0x10 /* Sync/hunt */
#define CTS 0x20 /* CTS */
#define TxEOM 0x40 /* Tx underrun */
#define BRK_ABRT 0x80 /* Break/Abort */
/* Read Register 1 */
#define ALL_SNT 0x1 /* All sent */
/* Residue Data for 8 Rx bits/char programmed */
#define RES3 0x8 /* 0/3 */
#define RES4 0x4 /* 0/4 */
#define RES5 0xc /* 0/5 */
#define RES6 0x2 /* 0/6 */
#define RES7 0xa /* 0/7 */
#define RES8 0x6 /* 0/8 */
#define RES18 0xe /* 1/8 */
#define RES28 0x0 /* 2/8 */
/* Special Rx Condition Interrupts */
#define PAR_ERR 0x10 /* Parity error */
#define Rx_OVR 0x20 /* Rx Overrun Error */
#define CRC_ERR 0x40 /* CRC/Framing Error */
#define END_FR 0x80 /* End of Frame (SDLC) */
/* Read Register 2 (channel b only) - Interrupt vector */
#define CHB_Tx_EMPTY 0x00
#define CHB_EXT_STAT 0x02
#define CHB_Rx_AVAIL 0x04
#define CHB_SPECIAL 0x06
#define CHA_Tx_EMPTY 0x08
#define CHA_EXT_STAT 0x0a
#define CHA_Rx_AVAIL 0x0c
#define CHA_SPECIAL 0x0e
#define STATUS_MASK 0x06
/* Read Register 3 (interrupt pending register) ch a only */
#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
#define CHBTxIP 0x2 /* Channel B Tx IP */
#define CHBRxIP 0x4 /* Channel B Rx IP */
#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
#define CHATxIP 0x10 /* Channel A Tx IP */
#define CHARxIP 0x20 /* Channel A Rx IP */
/* Read Register 8 (receive data register) */
/* Read Register 10 (misc status bits) */
#define ONLOOP 2 /* On loop */
#define LOOPSEND 0x10 /* Loop sending */
#define CLK2MIS 0x40 /* Two clocks missing */
#define CLK1MIS 0x80 /* One clock missing */
/* Read Register 12 (lower byte of baud rate generator constant) */
/* Read Register 13 (upper byte of baud rate generator constant) */
/* Read Register 15 (value of WR 15) */
/* Misc macros */
#define ZS_CLEARERR(port) (write_zsreg(port, 0, ERR_RES))
#define ZS_CLEARFIFO(port) do { volatile unsigned char garbage; \
garbage = read_zsdata(port); \
garbage = read_zsdata(port); \
garbage = read_zsdata(port); \
} while(0)
#define ZS_IS_CONS(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CONS)
#define ZS_IS_KGDB(UP) ((UP)->flags & PMACZILOG_FLAG_IS_KGDB)
#define ZS_IS_CHANNEL_A(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CHANNEL_A)
#define ZS_REGS_HELD(UP) ((UP)->flags & PMACZILOG_FLAG_REGS_HELD)
#define ZS_TX_STOPPED(UP) ((UP)->flags & PMACZILOG_FLAG_TX_STOPPED)
#define ZS_TX_ACTIVE(UP) ((UP)->flags & PMACZILOG_FLAG_TX_ACTIVE)
#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
#define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
#define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
#define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
#define ZS_IS_ASLEEP(UP) ((UP)->flags & PMACZILOG_FLAG_IS_ASLEEP)
#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
#define ZS_IS_IRQ_ON(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRQ_ON)
#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)
#endif /* __PMAC_ZILOG_H__ */

View File

@@ -0,0 +1,877 @@
/*
* linux/drivers/serial/pxa.c
*
* Based on drivers/serial/8250.c by Russell King.
*
* Author: Nicolas Pitre
* Created: Feb 20, 2003
* Copyright: (C) 2003 Monta Vista Software, Inc.
*
* 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.
*
* Note 1: This driver is made separate from the already too overloaded
* 8250.c because it needs some kirks of its own and that'll make it
* easier to add DMA support.
*
* Note 2: I'm too sick of device allocation policies for serial ports.
* If someone else wants to request an "official" allocation of major/minor
* for this driver please be my guest. And don't forget that new hardware
* to come from Intel might have more than 3 or 4 of those UARTs. Let's
* hope for a better port registration and dynamic device allocation scheme
* with the serial core maintainer satisfaction to appear soon.
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/serial_reg.h>
#include <linux/circ_buf.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pxa-regs.h>
struct uart_pxa_port {
struct uart_port port;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned int lsr_break_flag;
unsigned int cken;
char *name;
};
static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
{
offset <<= 2;
return readl(up->port.membase + offset);
}
static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
{
offset <<= 2;
writel(value, up->port.membase + offset);
}
static void serial_pxa_enable_ms(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
}
static void serial_pxa_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
if (up->ier & UART_IER_THRI) {
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
}
static void serial_pxa_stop_rx(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
}
static inline void
receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
{
struct tty_struct *tty = up->port.info->tty;
unsigned int ch, flag;
int max_count = 256;
do {
if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
if (tty->low_latency)
tty_flip_buffer_push(tty);
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts
*/
}
ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE))) {
/*
* For statistics only
*/
if (*status & UART_LSR_BI) {
*status &= ~(UART_LSR_FE | UART_LSR_PE);
up->port.icount.brk++;
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
* or read_status_mask.
*/
if (uart_handle_break(&up->port))
goto ignore_char;
} else if (*status & UART_LSR_PE)
up->port.icount.parity++;
else if (*status & UART_LSR_FE)
up->port.icount.frame++;
if (*status & UART_LSR_OE)
up->port.icount.overrun++;
/*
* Mask off conditions which should be ignored.
*/
*status &= up->port.read_status_mask;
#ifdef CONFIG_SERIAL_PXA_CONSOLE
if (up->port.line == up->port.cons->index) {
/* Recover the break flag from console xmit */
*status |= up->lsr_break_flag;
up->lsr_break_flag = 0;
}
#endif
if (*status & UART_LSR_BI) {
flag = TTY_BREAK;
} else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
else if (*status & UART_LSR_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag);
}
if ((*status & UART_LSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char:
*status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
tty_flip_buffer_push(tty);
}
static void transmit_chars(struct uart_pxa_port *up)
{
struct circ_buf *xmit = &up->port.info->xmit;
int count;
if (up->port.x_char) {
serial_out(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
up->port.x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
serial_pxa_stop_tx(&up->port, 0);
return;
}
count = up->port.fifosize / 2;
do {
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
up->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
if (uart_circ_empty(xmit))
serial_pxa_stop_tx(&up->port, 0);
}
static void serial_pxa_start_tx(struct uart_port *port, unsigned int tty_start)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
}
static inline void check_modem_status(struct uart_pxa_port *up)
{
int status;
status = serial_in(up, UART_MSR);
if ((status & UART_MSR_ANY_DELTA) == 0)
return;
if (status & UART_MSR_TERI)
up->port.icount.rng++;
if (status & UART_MSR_DDSR)
up->port.icount.dsr++;
if (status & UART_MSR_DDCD)
uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
if (status & UART_MSR_DCTS)
uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
wake_up_interruptible(&up->port.info->delta_msr_wait);
}
/*
* This handles the interrupt from one port.
*/
static inline irqreturn_t
serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id;
unsigned int iir, lsr;
iir = serial_in(up, UART_IIR);
if (iir & UART_IIR_NO_INT)
return IRQ_NONE;
lsr = serial_in(up, UART_LSR);
if (lsr & UART_LSR_DR)
receive_chars(up, &lsr, regs);
check_modem_status(up);
if (lsr & UART_LSR_THRE)
transmit_chars(up);
return IRQ_HANDLED;
}
static unsigned int serial_pxa_tx_empty(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
unsigned int ret;
spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
return ret;
}
static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
unsigned char status;
unsigned int ret;
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
spin_lock_irqsave(&up->port.lock, flags);
status = serial_in(up, UART_MSR);
spin_unlock_irqrestore(&up->port.lock, flags);
ret = 0;
if (status & UART_MSR_DCD)
ret |= TIOCM_CAR;
if (status & UART_MSR_RI)
ret |= TIOCM_RNG;
if (status & UART_MSR_DSR)
ret |= TIOCM_DSR;
if (status & UART_MSR_CTS)
ret |= TIOCM_CTS;
return ret;
}
static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned char mcr = 0;
if (mctrl & TIOCM_RTS)
mcr |= UART_MCR_RTS;
if (mctrl & TIOCM_DTR)
mcr |= UART_MCR_DTR;
if (mctrl & TIOCM_OUT1)
mcr |= UART_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
mcr |= UART_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
mcr |= up->mcr;
serial_out(up, UART_MCR, mcr);
}
static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
else
up->lcr &= ~UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
}
#if 0
static void serial_pxa_dma_init(struct pxa_uart *up)
{
up->rxdma =
pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
if (up->rxdma < 0)
goto out;
up->txdma =
pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
if (up->txdma < 0)
goto err_txdma;
up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
if (!up->dmadesc)
goto err_alloc;
/* ... */
err_alloc:
pxa_free_dma(up->txdma);
err_rxdma:
pxa_free_dma(up->rxdma);
out:
return;
}
#endif
static int serial_pxa_startup(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
int retval;
up->mcr = 0;
/*
* Allocate the IRQ
*/
retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
if (retval)
return retval;
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
*/
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);
/*
* Clear the interrupt registers.
*/
(void) serial_in(up, UART_LSR);
(void) serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);
/*
* Now, initialize the UART
*/
serial_out(up, UART_LCR, UART_LCR_WLEN8);
spin_lock_irqsave(&up->port.lock, flags);
up->port.mctrl |= TIOCM_OUT2;
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occuring imminently
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
serial_out(up, UART_IER, up->ier);
/*
* And clear the interrupt registers again for luck.
*/
(void) serial_in(up, UART_LSR);
(void) serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);
return 0;
}
static void serial_pxa_shutdown(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
free_irq(up->port.irq, up);
/*
* Disable interrupts from this port
*/
up->ier = 0;
serial_out(up, UART_IER, 0);
spin_lock_irqsave(&up->port.lock, flags);
up->port.mctrl &= ~TIOCM_OUT2;
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
/*
* Disable break condition and FIFOs
*/
serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);
}
static void
serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
case CS5:
cval = 0x00;
break;
case CS6:
cval = 0x01;
break;
case CS7:
cval = 0x02;
break;
default:
case CS8:
cval = 0x03;
break;
}
if (termios->c_cflag & CSTOPB)
cval |= 0x04;
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
if ((up->port.uartclk / quot) < (2400 * 16))
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
spin_lock_irqsave(&up->port.lock, flags);
/*
* Ensure the port will be enabled.
* This is required especially for serial console.
*/
up->ier |= IER_UUE;
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, quot);
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/*
* Characters to ignore
*/
up->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (termios->c_iflag & IGNBRK) {
up->port.ignore_status_mask |= UART_LSR_BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_OE;
}
/*
* ignore all characters if CREAD is not set
*/
if ((termios->c_cflag & CREAD) == 0)
up->port.ignore_status_mask |= UART_LSR_DR;
/*
* CTS flow control flag and modem status interrupts
*/
up->ier &= ~UART_IER_MSI;
if (UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
serial_out(up, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
serial_out(up, UART_FCR, fcr);
spin_unlock_irqrestore(&up->port.lock, flags);
}
static void
serial_pxa_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
pxa_set_cken(up->cken, !state);
if (!state)
udelay(1);
}
static void serial_pxa_release_port(struct uart_port *port)
{
}
static int serial_pxa_request_port(struct uart_port *port)
{
return 0;
}
static void serial_pxa_config_port(struct uart_port *port, int flags)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
up->port.type = PORT_PXA;
}
static int
serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
{
/* we don't want the core code to modify any port params */
return -EINVAL;
}
static const char *
serial_pxa_type(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
return up->name;
}
#ifdef CONFIG_SERIAL_PXA_CONSOLE
extern struct uart_pxa_port serial_pxa_ports[];
extern struct uart_driver serial_pxa_reg;
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Wait for transmitter & holding register to empty
*/
static inline void wait_for_xmitr(struct uart_pxa_port *up)
{
unsigned int status, tmout = 10000;
/* Wait up to 10ms for the character(s) to be sent. */
do {
status = serial_in(up, UART_LSR);
if (status & UART_LSR_BI)
up->lsr_break_flag = UART_LSR_BI;
if (--tmout == 0)
break;
udelay(1);
} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
tmout = 1000000;
while (--tmout &&
((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
udelay(1);
}
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* The console_lock must be held when we get here.
*/
static void
serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_pxa_port *up = &serial_pxa_ports[co->index];
unsigned int ier;
int i;
/*
* First save the UER then disable the interrupts
*/
ier = serial_in(up, UART_IER);
serial_out(up, UART_IER, UART_IER_UUE);
/*
* Now, do each character
*/
for (i = 0; i < count; i++, s++) {
wait_for_xmitr(up);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_out(up, UART_TX, *s);
if (*s == 10) {
wait_for_xmitr(up);
serial_out(up, UART_TX, 13);
}
}
/*
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(up);
serial_out(up, UART_IER, ier);
}
static int __init
serial_pxa_console_setup(struct console *co, char *options)
{
struct uart_pxa_port *up;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index == -1 || co->index >= serial_pxa_reg.nr)
co->index = 0;
up = &serial_pxa_ports[co->index];
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(&up->port, co, baud, parity, bits, flow);
}
static struct console serial_pxa_console = {
.name = "ttyS",
.write = serial_pxa_console_write,
.device = uart_console_device,
.setup = serial_pxa_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial_pxa_reg,
};
static int __init
serial_pxa_console_init(void)
{
register_console(&serial_pxa_console);
return 0;
}
console_initcall(serial_pxa_console_init);
#define PXA_CONSOLE &serial_pxa_console
#else
#define PXA_CONSOLE NULL
#endif
struct uart_ops serial_pxa_pops = {
.tx_empty = serial_pxa_tx_empty,
.set_mctrl = serial_pxa_set_mctrl,
.get_mctrl = serial_pxa_get_mctrl,
.stop_tx = serial_pxa_stop_tx,
.start_tx = serial_pxa_start_tx,
.stop_rx = serial_pxa_stop_rx,
.enable_ms = serial_pxa_enable_ms,
.break_ctl = serial_pxa_break_ctl,
.startup = serial_pxa_startup,
.shutdown = serial_pxa_shutdown,
.set_termios = serial_pxa_set_termios,
.pm = serial_pxa_pm,
.type = serial_pxa_type,
.release_port = serial_pxa_release_port,
.request_port = serial_pxa_request_port,
.config_port = serial_pxa_config_port,
.verify_port = serial_pxa_verify_port,
};
static struct uart_pxa_port serial_pxa_ports[] = {
{ /* FFUART */
.name = "FFUART",
.cken = CKEN6_FFUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
.membase = (void *)&FFUART,
.mapbase = __PREG(FFUART),
.irq = IRQ_FFUART,
.uartclk = 921600 * 16,
.fifosize = 64,
.ops = &serial_pxa_pops,
.line = 0,
},
}, { /* BTUART */
.name = "BTUART",
.cken = CKEN7_BTUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
.membase = (void *)&BTUART,
.mapbase = __PREG(BTUART),
.irq = IRQ_BTUART,
.uartclk = 921600 * 16,
.fifosize = 64,
.ops = &serial_pxa_pops,
.line = 1,
},
}, { /* STUART */
.name = "STUART",
.cken = CKEN5_STUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
.membase = (void *)&STUART,
.mapbase = __PREG(STUART),
.irq = IRQ_STUART,
.uartclk = 921600 * 16,
.fifosize = 64,
.ops = &serial_pxa_pops,
.line = 2,
},
}
};
static struct uart_driver serial_pxa_reg = {
.owner = THIS_MODULE,
.driver_name = "PXA serial",
.devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = ARRAY_SIZE(serial_pxa_ports),
.cons = PXA_CONSOLE,
};
static int serial_pxa_suspend(struct device *_dev, u32 state, u32 level)
{
struct uart_pxa_port *sport = dev_get_drvdata(_dev);
if (sport && level == SUSPEND_DISABLE)
uart_suspend_port(&serial_pxa_reg, &sport->port);
return 0;
}
static int serial_pxa_resume(struct device *_dev, u32 level)
{
struct uart_pxa_port *sport = dev_get_drvdata(_dev);
if (sport && level == RESUME_ENABLE)
uart_resume_port(&serial_pxa_reg, &sport->port);
return 0;
}
static int serial_pxa_probe(struct device *_dev)
{
struct platform_device *dev = to_platform_device(_dev);
serial_pxa_ports[dev->id].port.dev = _dev;
uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]);
return 0;
}
static int serial_pxa_remove(struct device *_dev)
{
struct uart_pxa_port *sport = dev_get_drvdata(_dev);
dev_set_drvdata(_dev, NULL);
if (sport)
uart_remove_one_port(&serial_pxa_reg, &sport->port);
return 0;
}
static struct device_driver serial_pxa_driver = {
.name = "pxa2xx-uart",
.bus = &platform_bus_type,
.probe = serial_pxa_probe,
.remove = serial_pxa_remove,
.suspend = serial_pxa_suspend,
.resume = serial_pxa_resume,
};
int __init serial_pxa_init(void)
{
int ret;
ret = uart_register_driver(&serial_pxa_reg);
if (ret != 0)
return ret;
ret = driver_register(&serial_pxa_driver);
if (ret != 0)
uart_unregister_driver(&serial_pxa_reg);
return ret;
}
void __exit serial_pxa_exit(void)
{
driver_unregister(&serial_pxa_driver);
uart_unregister_driver(&serial_pxa_reg);
}
module_init(serial_pxa_init);
module_exit(serial_pxa_exit);
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,952 @@
/*
* linux/drivers/char/sa1100.c
*
* Driver for SA11x0 serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* Copyright (C) 2000 Deep Blue Solutions Ltd.
*
* 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
*
* $Id: sa1100.c,v 1.50 2002/07/29 14:41:04 rmk Exp $
*
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/mach/serial_sa1100.h>
/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_SA1100_MAJOR 204
#define MINOR_START 5
#define NR_PORTS 3
#define SA1100_ISR_PASS_LIMIT 256
/*
* Convert from ignore_status_mask or read_status_mask to UTSR[01]
*/
#define SM_TO_UTSR0(x) ((x) & 0xff)
#define SM_TO_UTSR1(x) ((x) >> 8)
#define UTSR0_TO_SM(x) ((x))
#define UTSR1_TO_SM(x) ((x) << 8)
#define UART_GET_UTCR0(sport) __raw_readl((sport)->port.membase + UTCR0)
#define UART_GET_UTCR1(sport) __raw_readl((sport)->port.membase + UTCR1)
#define UART_GET_UTCR2(sport) __raw_readl((sport)->port.membase + UTCR2)
#define UART_GET_UTCR3(sport) __raw_readl((sport)->port.membase + UTCR3)
#define UART_GET_UTSR0(sport) __raw_readl((sport)->port.membase + UTSR0)
#define UART_GET_UTSR1(sport) __raw_readl((sport)->port.membase + UTSR1)
#define UART_GET_CHAR(sport) __raw_readl((sport)->port.membase + UTDR)
#define UART_PUT_UTCR0(sport,v) __raw_writel((v),(sport)->port.membase + UTCR0)
#define UART_PUT_UTCR1(sport,v) __raw_writel((v),(sport)->port.membase + UTCR1)
#define UART_PUT_UTCR2(sport,v) __raw_writel((v),(sport)->port.membase + UTCR2)
#define UART_PUT_UTCR3(sport,v) __raw_writel((v),(sport)->port.membase + UTCR3)
#define UART_PUT_UTSR0(sport,v) __raw_writel((v),(sport)->port.membase + UTSR0)
#define UART_PUT_UTSR1(sport,v) __raw_writel((v),(sport)->port.membase + UTSR1)
#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR)
/*
* This is the size of our serial port register set.
*/
#define UART_PORT_SIZE 0x24
/*
* This determines how often we check the modem status signals
* for any change. They generally aren't connected to an IRQ
* so we have to poll them. We also check immediately before
* filling the TX fifo incase CTS has been dropped.
*/
#define MCTRL_TIMEOUT (250*HZ/1000)
struct sa1100_port {
struct uart_port port;
struct timer_list timer;
unsigned int old_status;
};
/*
* Handle any change of modem status signal since we were last called.
*/
static void sa1100_mctrl_check(struct sa1100_port *sport)
{
unsigned int status, changed;
status = sport->port.ops->get_mctrl(&sport->port);
changed = status ^ sport->old_status;
if (changed == 0)
return;
sport->old_status = status;
if (changed & TIOCM_RI)
sport->port.icount.rng++;
if (changed & TIOCM_DSR)
sport->port.icount.dsr++;
if (changed & TIOCM_CAR)
uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
if (changed & TIOCM_CTS)
uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
wake_up_interruptible(&sport->port.info->delta_msr_wait);
}
/*
* This is our per-port timeout handler, for checking the
* modem status signals.
*/
static void sa1100_timeout(unsigned long data)
{
struct sa1100_port *sport = (struct sa1100_port *)data;
unsigned long flags;
if (sport->port.info) {
spin_lock_irqsave(&sport->port.lock, flags);
sa1100_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
}
}
/*
* interrupts disabled on entry
*/
static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
u32 utcr3;
utcr3 = UART_GET_UTCR3(sport);
UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
}
/*
* interrupts may not be disabled on entry
*/
static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
u32 utcr3;
spin_lock_irqsave(&sport->port.lock, flags);
utcr3 = UART_GET_UTCR3(sport);
sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
* Interrupts enabled
*/
static void sa1100_stop_rx(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
u32 utcr3;
utcr3 = UART_GET_UTCR3(sport);
UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
}
/*
* Set the modem control timer to fire immediately.
*/
static void sa1100_enable_ms(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
mod_timer(&sport->timer, jiffies);
}
static void
sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
{
struct tty_struct *tty = sport->port.info->tty;
unsigned int status, ch, flg, ignored = 0;
status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
UTSR0_TO_SM(UART_GET_UTSR0(sport));
while (status & UTSR1_TO_SM(UTSR1_RNE)) {
ch = UART_GET_CHAR(sport);
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
goto ignore_char;
sport->port.icount.rx++;
flg = TTY_NORMAL;
/*
* note that the error handling code is
* out of the main execution path
*/
if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR))
goto handle_error;
if (uart_handle_sysrq_char(&sport->port, ch, regs))
goto ignore_char;
error_return:
tty_insert_flip_char(tty, ch, flg);
ignore_char:
status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
UTSR0_TO_SM(UART_GET_UTSR0(sport));
}
out:
tty_flip_buffer_push(tty);
return;
handle_error:
if (status & UTSR1_TO_SM(UTSR1_PRE))
sport->port.icount.parity++;
else if (status & UTSR1_TO_SM(UTSR1_FRE))
sport->port.icount.frame++;
if (status & UTSR1_TO_SM(UTSR1_ROR))
sport->port.icount.overrun++;
if (status & sport->port.ignore_status_mask) {
if (++ignored > 100)
goto out;
goto ignore_char;
}
status &= sport->port.read_status_mask;
if (status & UTSR1_TO_SM(UTSR1_PRE))
flg = TTY_PARITY;
else if (status & UTSR1_TO_SM(UTSR1_FRE))
flg = TTY_FRAME;
if (status & UTSR1_TO_SM(UTSR1_ROR)) {
/*
* overrun does *not* affect the character
* we read from the FIFO
*/
tty_insert_flip_char(tty, ch, flg);
ch = 0;
flg = TTY_OVERRUN;
}
#ifdef SUPPORT_SYSRQ
sport->port.sysrq = 0;
#endif
goto error_return;
}
static void sa1100_tx_chars(struct sa1100_port *sport)
{
struct circ_buf *xmit = &sport->port.info->xmit;
if (sport->port.x_char) {
UART_PUT_CHAR(sport, sport->port.x_char);
sport->port.icount.tx++;
sport->port.x_char = 0;
return;
}
/*
* Check the modem control lines before
* transmitting anything.
*/
sa1100_mctrl_check(sport);
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
sa1100_stop_tx(&sport->port, 0);
return;
}
/*
* Tried using FIFO (not checking TNF) for fifo fill:
* still had the '4 bytes repeated' problem.
*/
while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit))
sa1100_stop_tx(&sport->port, 0);
}
static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct sa1100_port *sport = dev_id;
unsigned int status, pass_counter = 0;
spin_lock(&sport->port.lock);
status = UART_GET_UTSR0(sport);
status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
do {
if (status & (UTSR0_RFS | UTSR0_RID)) {
/* Clear the receiver idle bit, if set */
if (status & UTSR0_RID)
UART_PUT_UTSR0(sport, UTSR0_RID);
sa1100_rx_chars(sport, regs);
}
/* Clear the relevant break bits */
if (status & (UTSR0_RBB | UTSR0_REB))
UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
if (status & UTSR0_RBB)
sport->port.icount.brk++;
if (status & UTSR0_REB)
uart_handle_break(&sport->port);
if (status & UTSR0_TFS)
sa1100_tx_chars(sport);
if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
break;
status = UART_GET_UTSR0(sport);
status &= SM_TO_UTSR0(sport->port.read_status_mask) |
~UTSR0_TFS;
} while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
spin_unlock(&sport->port.lock);
return IRQ_HANDLED;
}
/*
* Return TIOCSER_TEMT when transmitter is not busy.
*/
static unsigned int sa1100_tx_empty(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
}
static unsigned int sa1100_get_mctrl(struct uart_port *port)
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
/*
* Interrupts always disabled.
*/
static void sa1100_break_ctl(struct uart_port *port, int break_state)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
unsigned int utcr3;
spin_lock_irqsave(&sport->port.lock, flags);
utcr3 = UART_GET_UTCR3(sport);
if (break_state == -1)
utcr3 |= UTCR3_BRK;
else
utcr3 &= ~UTCR3_BRK;
UART_PUT_UTCR3(sport, utcr3);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static int sa1100_startup(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
int retval;
/*
* Allocate the IRQ
*/
retval = request_irq(sport->port.irq, sa1100_int, 0,
"sa11x0-uart", sport);
if (retval)
return retval;
/*
* Finally, clear and enable interrupts
*/
UART_PUT_UTSR0(sport, -1);
UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
/*
* Enable modem status interrupts
*/
spin_lock_irq(&sport->port.lock);
sa1100_enable_ms(&sport->port);
spin_unlock_irq(&sport->port.lock);
return 0;
}
static void sa1100_shutdown(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
/*
* Stop our timer.
*/
del_timer_sync(&sport->timer);
/*
* Free the interrupt
*/
free_irq(sport->port.irq, sport);
/*
* Disable all interrupts, port and break condition.
*/
UART_PUT_UTCR3(sport, 0);
}
static void
sa1100_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
unsigned int utcr0, old_utcr3, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
/*
* We only support CS7 and CS8.
*/
while ((termios->c_cflag & CSIZE) != CS7 &&
(termios->c_cflag & CSIZE) != CS8) {
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= old_csize;
old_csize = CS8;
}
if ((termios->c_cflag & CSIZE) == CS8)
utcr0 = UTCR0_DSS;
else
utcr0 = 0;
if (termios->c_cflag & CSTOPB)
utcr0 |= UTCR0_SBS;
if (termios->c_cflag & PARENB) {
utcr0 |= UTCR0_PE;
if (!(termios->c_cflag & PARODD))
utcr0 |= UTCR0_OES;
}
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&sport->port.lock, flags);
sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |=
UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
if (termios->c_iflag & (BRKINT | PARMRK))
sport->port.read_status_mask |=
UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
/*
* Characters to ignore
*/
sport->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |=
UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |=
UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB);
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |=
UTSR1_TO_SM(UTSR1_ROR);
}
del_timer_sync(&sport->timer);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
/*
* disable interrupts and drain transmitter
*/
old_utcr3 = UART_GET_UTCR3(sport);
UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
while (UART_GET_UTSR1(sport) & UTSR1_TBY)
barrier();
/* then, disable everything */
UART_PUT_UTCR3(sport, 0);
/* set the parity, stop bits and data size */
UART_PUT_UTCR0(sport, utcr0);
/* set the baud rate */
quot -= 1;
UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
UART_PUT_UTCR2(sport, (quot & 0xff));
UART_PUT_UTSR0(sport, -1);
UART_PUT_UTCR3(sport, old_utcr3);
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
sa1100_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static const char *sa1100_type(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
}
/*
* Release the memory region(s) being used by 'port'.
*/
static void sa1100_release_port(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
}
/*
* Request the memory region(s) being used by 'port'.
*/
static int sa1100_request_port(struct uart_port *port)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
"sa11x0-uart") != NULL ? 0 : -EBUSY;
}
/*
* Configure/autoconfigure the port.
*/
static void sa1100_config_port(struct uart_port *port, int flags)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
if (flags & UART_CONFIG_TYPE &&
sa1100_request_port(&sport->port) == 0)
sport->port.type = PORT_SA1100;
}
/*
* Verify the new serial_struct (for TIOCSSERIAL).
* The only change we allow are to the flags and type, and
* even then only between PORT_SA1100 and PORT_UNKNOWN
*/
static int
sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
ret = -EINVAL;
if (sport->port.irq != ser->irq)
ret = -EINVAL;
if (ser->io_type != SERIAL_IO_MEM)
ret = -EINVAL;
if (sport->port.uartclk / 16 != ser->baud_base)
ret = -EINVAL;
if ((void *)sport->port.mapbase != ser->iomem_base)
ret = -EINVAL;
if (sport->port.iobase != ser->port)
ret = -EINVAL;
if (ser->hub6 != 0)
ret = -EINVAL;
return ret;
}
static struct uart_ops sa1100_pops = {
.tx_empty = sa1100_tx_empty,
.set_mctrl = sa1100_set_mctrl,
.get_mctrl = sa1100_get_mctrl,
.stop_tx = sa1100_stop_tx,
.start_tx = sa1100_start_tx,
.stop_rx = sa1100_stop_rx,
.enable_ms = sa1100_enable_ms,
.break_ctl = sa1100_break_ctl,
.startup = sa1100_startup,
.shutdown = sa1100_shutdown,
.set_termios = sa1100_set_termios,
.type = sa1100_type,
.release_port = sa1100_release_port,
.request_port = sa1100_request_port,
.config_port = sa1100_config_port,
.verify_port = sa1100_verify_port,
};
static struct sa1100_port sa1100_ports[NR_PORTS];
/*
* Setup the SA1100 serial ports. Note that we don't include the IrDA
* port here since we have our own SIR/FIR driver (see drivers/net/irda)
*
* Note also that we support "console=ttySAx" where "x" is either 0 or 1.
* Which serial port this ends up being depends on the machine you're
* running this kernel on. I'm not convinced that this is a good idea,
* but that's the way it traditionally works.
*
* Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
* used here.
*/
static void __init sa1100_init_ports(void)
{
static int first = 1;
int i;
if (!first)
return;
first = 0;
for (i = 0; i < NR_PORTS; i++) {
sa1100_ports[i].port.uartclk = 3686400;
sa1100_ports[i].port.ops = &sa1100_pops;
sa1100_ports[i].port.fifosize = 8;
sa1100_ports[i].port.line = i;
sa1100_ports[i].port.iotype = SERIAL_IO_MEM;
init_timer(&sa1100_ports[i].timer);
sa1100_ports[i].timer.function = sa1100_timeout;
sa1100_ports[i].timer.data = (unsigned long)&sa1100_ports[i];
}
/*
* make transmit lines outputs, so that when the port
* is closed, the output is in the MARK state.
*/
PPDR |= PPC_TXD1 | PPC_TXD3;
PPSR |= PPC_TXD1 | PPC_TXD3;
}
void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns)
{
if (fns->get_mctrl)
sa1100_pops.get_mctrl = fns->get_mctrl;
if (fns->set_mctrl)
sa1100_pops.set_mctrl = fns->set_mctrl;
sa1100_pops.pm = fns->pm;
sa1100_pops.set_wake = fns->set_wake;
}
void __init sa1100_register_uart(int idx, int port)
{
if (idx >= NR_PORTS) {
printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx);
return;
}
switch (port) {
case 1:
sa1100_ports[idx].port.membase = (void *)&Ser1UTCR0;
sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
sa1100_ports[idx].port.irq = IRQ_Ser1UART;
sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
break;
case 2:
sa1100_ports[idx].port.membase = (void *)&Ser2UTCR0;
sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
sa1100_ports[idx].port.irq = IRQ_Ser2ICP;
sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
break;
case 3:
sa1100_ports[idx].port.membase = (void *)&Ser3UTCR0;
sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
sa1100_ports[idx].port.irq = IRQ_Ser3UART;
sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF;
break;
default:
printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port);
}
}
#ifdef CONFIG_SERIAL_SA1100_CONSOLE
/*
* Interrupts are disabled on entering
*/
static void
sa1100_console_write(struct console *co, const char *s, unsigned int count)
{
struct sa1100_port *sport = &sa1100_ports[co->index];
unsigned int old_utcr3, status, i;
/*
* First, save UTCR3 and then disable interrupts
*/
old_utcr3 = UART_GET_UTCR3(sport);
UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
UTCR3_TXE);
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
do {
status = UART_GET_UTSR1(sport);
} while (!(status & UTSR1_TNF));
UART_PUT_CHAR(sport, s[i]);
if (s[i] == '\n') {
do {
status = UART_GET_UTSR1(sport);
} while (!(status & UTSR1_TNF));
UART_PUT_CHAR(sport, '\r');
}
}
/*
* Finally, wait for transmitter to become empty
* and restore UTCR3
*/
do {
status = UART_GET_UTSR1(sport);
} while (status & UTSR1_TBY);
UART_PUT_UTCR3(sport, old_utcr3);
}
/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
*/
static void __init
sa1100_console_get_options(struct sa1100_port *sport, int *baud,
int *parity, int *bits)
{
unsigned int utcr3;
utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
/* ok, the port was enabled */
unsigned int utcr0, quot;
utcr0 = UART_GET_UTCR0(sport);
*parity = 'n';
if (utcr0 & UTCR0_PE) {
if (utcr0 & UTCR0_OES)
*parity = 'e';
else
*parity = 'o';
}
if (utcr0 & UTCR0_DSS)
*bits = 8;
else
*bits = 7;
quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
quot &= 0xfff;
*baud = sport->port.uartclk / (16 * (quot + 1));
}
}
static int __init
sa1100_console_setup(struct console *co, char *options)
{
struct sa1100_port *sport;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index == -1 || co->index >= NR_PORTS)
co->index = 0;
sport = &sa1100_ports[co->index];
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
sa1100_console_get_options(sport, &baud, &parity, &bits);
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
}
extern struct uart_driver sa1100_reg;
static struct console sa1100_console = {
.name = "ttySA",
.write = sa1100_console_write,
.device = uart_console_device,
.setup = sa1100_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &sa1100_reg,
};
static int __init sa1100_rs_console_init(void)
{
sa1100_init_ports();
register_console(&sa1100_console);
return 0;
}
console_initcall(sa1100_rs_console_init);
#define SA1100_CONSOLE &sa1100_console
#else
#define SA1100_CONSOLE NULL
#endif
static struct uart_driver sa1100_reg = {
.owner = THIS_MODULE,
.driver_name = "ttySA",
.dev_name = "ttySA",
.devfs_name = "ttySA",
.major = SERIAL_SA1100_MAJOR,
.minor = MINOR_START,
.nr = NR_PORTS,
.cons = SA1100_CONSOLE,
};
static int sa1100_serial_suspend(struct device *_dev, u32 state, u32 level)
{
struct sa1100_port *sport = dev_get_drvdata(_dev);
if (sport && level == SUSPEND_DISABLE)
uart_suspend_port(&sa1100_reg, &sport->port);
return 0;
}
static int sa1100_serial_resume(struct device *_dev, u32 level)
{
struct sa1100_port *sport = dev_get_drvdata(_dev);
if (sport && level == RESUME_ENABLE)
uart_resume_port(&sa1100_reg, &sport->port);
return 0;
}
static int sa1100_serial_probe(struct device *_dev)
{
struct platform_device *dev = to_platform_device(_dev);
struct resource *res = dev->resource;
int i;
for (i = 0; i < dev->num_resources; i++, res++)
if (res->flags & IORESOURCE_MEM)
break;
if (i < dev->num_resources) {
for (i = 0; i < NR_PORTS; i++) {
if (sa1100_ports[i].port.mapbase != res->start)
continue;
sa1100_ports[i].port.dev = _dev;
uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
dev_set_drvdata(_dev, &sa1100_ports[i]);
break;
}
}
return 0;
}
static int sa1100_serial_remove(struct device *_dev)
{
struct sa1100_port *sport = dev_get_drvdata(_dev);
dev_set_drvdata(_dev, NULL);
if (sport)
uart_remove_one_port(&sa1100_reg, &sport->port);
return 0;
}
static struct device_driver sa11x0_serial_driver = {
.name = "sa11x0-uart",
.bus = &platform_bus_type,
.probe = sa1100_serial_probe,
.remove = sa1100_serial_remove,
.suspend = sa1100_serial_suspend,
.resume = sa1100_serial_resume,
};
static int __init sa1100_serial_init(void)
{
int ret;
printk(KERN_INFO "Serial: SA11x0 driver $Revision: 1.50 $\n");
sa1100_init_ports();
ret = uart_register_driver(&sa1100_reg);
if (ret == 0) {
ret = driver_register(&sa11x0_serial_driver);
if (ret)
uart_unregister_driver(&sa1100_reg);
}
return ret;
}
static void __exit sa1100_serial_exit(void)
{
driver_unregister(&sa11x0_serial_driver);
uart_unregister_driver(&sa1100_reg);
}
module_init(sa1100_serial_init);
module_exit(sa1100_serial_exit);
MODULE_AUTHOR("Deep Blue Solutions Ltd");
MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.50 $");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_SA1100_MAJOR);

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,761 @@
/*======================================================================
A driver for PCMCIA serial devices
serial_cs.c 1.134 2002/05/04 05:48:53
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU General Public License version 2 (the "GPL"), in which
case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
by deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
======================================================================*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/serial_core.h>
#include <linux/major.h>
#include <asm/io.h>
#include <asm/system.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
#include "8250.h"
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
module_param(pc_debug, int, 0644);
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xdeb8;
static int irq_list[4];
static unsigned int irq_list_count;
/* Enable the speaker? */
static int do_sound = 1;
/* Skip strict UART tests? */
static int buggy_uart;
module_param(irq_mask, uint, 0444);
module_param_array(irq_list, int, &irq_list_count, 0444);
module_param(do_sound, int, 0444);
module_param(buggy_uart, int, 0444);
/*====================================================================*/
/* Table of multi-port card ID's */
struct multi_id {
u_short manfid;
u_short prodid;
int multi; /* 1 = multifunction, > 1 = # ports */
};
static struct multi_id multi_id[] = {
{ MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
{ MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
{ MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
{ MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
{ MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
{ MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
{ MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
};
#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
struct serial_info {
dev_link_t link;
int ndev;
int multi;
int slave;
int manfid;
dev_node_t node[4];
int line[4];
};
static void serial_config(dev_link_t * link);
static int serial_event(event_t event, int priority,
event_callback_args_t * args);
static dev_info_t dev_info = "serial_cs";
static dev_link_t *serial_attach(void);
static void serial_detach(dev_link_t *);
static dev_link_t *dev_list = NULL;
/*======================================================================
After a card is removed, serial_remove() will unregister
the serial device(s), and release the PCMCIA configuration.
======================================================================*/
static void serial_remove(dev_link_t *link)
{
struct serial_info *info = link->priv;
int i;
link->state &= ~DEV_PRESENT;
DEBUG(0, "serial_release(0x%p)\n", link);
/*
* Recheck to see if the device is still configured.
*/
if (info->link.state & DEV_CONFIG) {
for (i = 0; i < info->ndev; i++)
serial8250_unregister_port(info->line[i]);
info->link.dev = NULL;
if (!info->slave) {
pcmcia_release_configuration(info->link.handle);
pcmcia_release_io(info->link.handle, &info->link.io);
pcmcia_release_irq(info->link.handle, &info->link.irq);
}
info->link.state &= ~DEV_CONFIG;
}
}
static void serial_suspend(dev_link_t *link)
{
link->state |= DEV_SUSPEND;
if (link->state & DEV_CONFIG) {
struct serial_info *info = link->priv;
int i;
for (i = 0; i < info->ndev; i++)
serial8250_suspend_port(info->line[i]);
if (!info->slave)
pcmcia_release_configuration(link->handle);
}
}
static void serial_resume(dev_link_t *link)
{
link->state &= ~DEV_SUSPEND;
if (DEV_OK(link)) {
struct serial_info *info = link->priv;
int i;
if (!info->slave)
pcmcia_request_configuration(link->handle, &link->conf);
for (i = 0; i < info->ndev; i++)
serial8250_resume_port(info->line[i]);
}
}
/*======================================================================
serial_attach() creates an "instance" of the driver, allocating
local data structures for one device. The device is registered
with Card Services.
======================================================================*/
static dev_link_t *serial_attach(void)
{
struct serial_info *info;
client_reg_t client_reg;
dev_link_t *link;
int i, ret;
DEBUG(0, "serial_attach()\n");
/* Create new serial device */
info = kmalloc(sizeof (*info), GFP_KERNEL);
if (!info)
return NULL;
memset(info, 0, sizeof (*info));
link = &info->link;
link->priv = info;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
if (irq_list_count == 0)
link->irq.IRQInfo2 = irq_mask;
else
for (i = 0; i < irq_list_count; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i];
link->conf.Attributes = CONF_ENABLE_IRQ;
if (do_sound) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
link->conf.IntType = INT_MEMORY_AND_IO;
/* Register with Card Services */
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
client_reg.EventMask =
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.event_handler = &serial_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
if (ret != CS_SUCCESS) {
cs_error(link->handle, RegisterClient, ret);
serial_detach(link);
return NULL;
}
return link;
}
/*======================================================================
This deletes a driver "instance". The device is de-registered
with Card Services. If it has been released, all local data
structures are freed. Otherwise, the structures will be freed
when the device is released.
======================================================================*/
static void serial_detach(dev_link_t * link)
{
struct serial_info *info = link->priv;
dev_link_t **linkp;
int ret;
DEBUG(0, "serial_detach(0x%p)\n", link);
/* Locate device structure */
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
if (*linkp == link)
break;
if (*linkp == NULL)
return;
/*
* Ensure any outstanding scheduled tasks are completed.
*/
flush_scheduled_work();
/*
* Ensure that the ports have been released.
*/
serial_remove(link);
if (link->handle) {
ret = pcmcia_deregister_client(link->handle);
if (ret != CS_SUCCESS)
cs_error(link->handle, DeregisterClient, ret);
}
/* Unlink device structure, free bits */
*linkp = link->next;
kfree(info);
}
/*====================================================================*/
static int setup_serial(struct serial_info * info, ioaddr_t iobase, int irq)
{
struct uart_port port;
int line;
memset(&port, 0, sizeof (struct uart_port));
port.iobase = iobase;
port.irq = irq;
port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
port.uartclk = 1843200;
if (buggy_uart)
port.flags |= UPF_BUGGY_UART;
line = serial8250_register_port(&port);
if (line < 0) {
printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
"0x%04lx, irq %d failed\n", (u_long)iobase, irq);
return -EINVAL;
}
info->line[info->ndev] = line;
sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
info->node[info->ndev].major = TTY_MAJOR;
info->node[info->ndev].minor = 0x40 + line;
if (info->ndev > 0)
info->node[info->ndev - 1].next = &info->node[info->ndev];
info->ndev++;
return 0;
}
/*====================================================================*/
static int
first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
{
int i;
i = pcmcia_get_first_tuple(handle, tuple);
if (i != CS_SUCCESS)
return CS_NO_MORE_ITEMS;
i = pcmcia_get_tuple_data(handle, tuple);
if (i != CS_SUCCESS)
return i;
return pcmcia_parse_tuple(handle, tuple, parse);
}
static int
next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
{
int i;
i = pcmcia_get_next_tuple(handle, tuple);
if (i != CS_SUCCESS)
return CS_NO_MORE_ITEMS;
i = pcmcia_get_tuple_data(handle, tuple);
if (i != CS_SUCCESS)
return i;
return pcmcia_parse_tuple(handle, tuple, parse);
}
/*====================================================================*/
static int simple_config(dev_link_t *link)
{
static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
static int size_table[2] = { 8, 16 };
client_handle_t handle = link->handle;
struct serial_info *info = link->priv;
tuple_t tuple;
u_char buf[256];
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
config_info_t config;
int i, j, try;
int s;
/* If the card is already configured, look up the port and irq */
i = pcmcia_get_configuration_info(handle, &config);
if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
ioaddr_t port = 0;
if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
port = config.BasePort2;
info->slave = 1;
} else if ((info->manfid == MANFID_OSITECH) &&
(config.NumPorts1 == 0x40)) {
port = config.BasePort1 + 0x28;
info->slave = 1;
}
if (info->slave)
return setup_serial(info, port, config.AssignedIRQ);
}
link->conf.Vcc = config.Vcc;
/* First pass: look for a config entry that looks normal. */
tuple.TupleData = (cisdata_t *) buf;
tuple.TupleOffset = 0;
tuple.TupleDataMax = 255;
tuple.Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
/* Two tries: without IO aliases, then with aliases */
for (s = 0; s < 2; s++) {
for (try = 0; try < 2; try++) {
i = first_tuple(handle, &tuple, &parse);
while (i != CS_NO_MORE_ITEMS) {
if (i != CS_SUCCESS)
goto next_entry;
if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
link->conf.Vpp1 = link->conf.Vpp2 =
cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
(cf->io.win[0].base != 0)) {
link->conf.ConfigIndex = cf->index;
link->io.BasePort1 = cf->io.win[0].base;
link->io.IOAddrLines = (try == 0) ?
16 : cf->io.flags & CISTPL_IO_LINES_MASK;
i = pcmcia_request_io(link->handle, &link->io);
if (i == CS_SUCCESS)
goto found_port;
}
next_entry:
i = next_tuple(handle, &tuple, &parse);
}
}
}
/* Second pass: try to find an entry that isn't picky about
its base address, then try to grab any standard serial port
address, and finally try to get any free port. */
i = first_tuple(handle, &tuple, &parse);
while (i != CS_NO_MORE_ITEMS) {
if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
link->conf.ConfigIndex = cf->index;
for (j = 0; j < 5; j++) {
link->io.BasePort1 = base[j];
link->io.IOAddrLines = base[j] ? 16 : 3;
i = pcmcia_request_io(link->handle, &link->io);
if (i == CS_SUCCESS)
goto found_port;
}
}
i = next_tuple(handle, &tuple, &parse);
}
found_port:
if (i != CS_SUCCESS) {
printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n");
cs_error(link->handle, RequestIO, i);
return -1;
}
i = pcmcia_request_irq(link->handle, &link->irq);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIRQ, i);
link->irq.AssignedIRQ = 0;
}
if (info->multi && (info->manfid == MANFID_3COM))
link->conf.ConfigIndex &= ~(0x08);
i = pcmcia_request_configuration(link->handle, &link->conf);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestConfiguration, i);
return -1;
}
return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
}
static int multi_config(dev_link_t * link)
{
client_handle_t handle = link->handle;
struct serial_info *info = link->priv;
tuple_t tuple;
u_char buf[256];
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
config_info_t config;
int i, base2 = 0;
i = pcmcia_get_configuration_info(handle, &config);
if (i != CS_SUCCESS) {
cs_error(handle, GetConfigurationInfo, i);
return -1;
}
link->conf.Vcc = config.Vcc;
tuple.TupleData = (cisdata_t *) buf;
tuple.TupleOffset = 0;
tuple.TupleDataMax = 255;
tuple.Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
/* First, look for a generic full-sized window */
link->io.NumPorts1 = info->multi * 8;
i = first_tuple(handle, &tuple, &parse);
while (i != CS_NO_MORE_ITEMS) {
/* The quad port cards have bad CIS's, so just look for a
window larger than 8 ports and assume it will be right */
if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
(cf->io.win[0].len > 8)) {
link->conf.ConfigIndex = cf->index;
link->io.BasePort1 = cf->io.win[0].base;
link->io.IOAddrLines =
cf->io.flags & CISTPL_IO_LINES_MASK;
i = pcmcia_request_io(link->handle, &link->io);
base2 = link->io.BasePort1 + 8;
if (i == CS_SUCCESS)
break;
}
i = next_tuple(handle, &tuple, &parse);
}
/* If that didn't work, look for two windows */
if (i != CS_SUCCESS) {
link->io.NumPorts1 = link->io.NumPorts2 = 8;
info->multi = 2;
i = first_tuple(handle, &tuple, &parse);
while (i != CS_NO_MORE_ITEMS) {
if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
link->conf.ConfigIndex = cf->index;
link->io.BasePort1 = cf->io.win[0].base;
link->io.BasePort2 = cf->io.win[1].base;
link->io.IOAddrLines =
cf->io.flags & CISTPL_IO_LINES_MASK;
i = pcmcia_request_io(link->handle, &link->io);
base2 = link->io.BasePort2;
if (i == CS_SUCCESS)
break;
}
i = next_tuple(handle, &tuple, &parse);
}
}
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIO, i);
return -1;
}
i = pcmcia_request_irq(link->handle, &link->irq);
if (i != CS_SUCCESS) {
printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n");
cs_error(link->handle, RequestIRQ, i);
link->irq.AssignedIRQ = 0;
}
/* Socket Dual IO: this enables irq's for second port */
if (info->multi && (info->manfid == MANFID_SOCKET)) {
link->conf.Present |= PRESENT_EXT_STATUS;
link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
}
i = pcmcia_request_configuration(link->handle, &link->conf);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestConfiguration, i);
return -1;
}
/* The Oxford Semiconductor OXCF950 cards are in fact single-port:
8 registers are for the UART, the others are extra registers */
if (info->manfid == MANFID_OXSEMI) {
if (cf->index == 1 || cf->index == 3) {
setup_serial(info, base2, link->irq.AssignedIRQ);
outb(12, link->io.BasePort1 + 1);
} else {
setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
outb(12, base2 + 1);
}
return 0;
}
setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
/* The Nokia cards are not really multiport cards */
if (info->manfid == MANFID_NOKIA)
return 0;
for (i = 0; i < info->multi - 1; i++)
setup_serial(info, base2 + (8 * i), link->irq.AssignedIRQ);
return 0;
}
/*======================================================================
serial_config() is scheduled to run after a CARD_INSERTION event
is received, to configure the PCMCIA socket, and to make the
serial device available to the system.
======================================================================*/
void serial_config(dev_link_t * link)
{
client_handle_t handle = link->handle;
struct serial_info *info = link->priv;
tuple_t tuple;
u_short buf[128];
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
int i, last_ret, last_fn;
DEBUG(0, "serial_config(0x%p)\n", link);
tuple.TupleData = (cisdata_t *) buf;
tuple.TupleOffset = 0;
tuple.TupleDataMax = 255;
tuple.Attributes = 0;
/* Get configuration register information */
tuple.DesiredTuple = CISTPL_CONFIG;
last_ret = first_tuple(handle, &tuple, &parse);
if (last_ret != CS_SUCCESS) {
last_fn = ParseTuple;
goto cs_failed;
}
link->conf.ConfigBase = parse.config.base;
link->conf.Present = parse.config.rmask[0];
/* Configure card */
link->state |= DEV_CONFIG;
/* Is this a compliant multifunction card? */
tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
/* Is this a multiport card? */
tuple.DesiredTuple = CISTPL_MANFID;
if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
info->manfid = le16_to_cpu(buf[0]);
for (i = 0; i < MULTI_COUNT; i++)
if ((info->manfid == multi_id[i].manfid) &&
(le16_to_cpu(buf[1]) == multi_id[i].prodid))
break;
if (i < MULTI_COUNT)
info->multi = multi_id[i].multi;
}
/* Another check for dual-serial cards: look for either serial or
multifunction cards that ask for appropriate IO port ranges */
tuple.DesiredTuple = CISTPL_FUNCID;
if ((info->multi == 0) &&
((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
(parse.funcid.func == CISTPL_FUNCID_MULTI) ||
(parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
info->multi = cf->io.win[0].len >> 3;
if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
(cf->io.win[1].len == 8))
info->multi = 2;
}
}
if (info->multi > 1)
multi_config(link);
else
simple_config(link);
if (info->ndev == 0)
goto failed;
if (info->manfid == MANFID_IBM) {
conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
last_ret = pcmcia_access_configuration_register(link->handle, &reg);
if (last_ret) {
last_fn = AccessConfigurationRegister;
goto cs_failed;
}
reg.Action = CS_WRITE;
reg.Value = reg.Value | 1;
last_ret = pcmcia_access_configuration_register(link->handle, &reg);
if (last_ret) {
last_fn = AccessConfigurationRegister;
goto cs_failed;
}
}
link->dev = &info->node[0];
link->state &= ~DEV_CONFIG_PENDING;
return;
cs_failed:
cs_error(link->handle, last_fn, last_ret);
failed:
serial_remove(link);
link->state &= ~DEV_CONFIG_PENDING;
}
/*======================================================================
The card status event handler. Mostly, this schedules other
stuff to run after an event is received. A CARD_REMOVAL event
also sets some flags to discourage the serial drivers from
talking to the ports.
======================================================================*/
static int
serial_event(event_t event, int priority, event_callback_args_t * args)
{
dev_link_t *link = args->client_data;
struct serial_info *info = link->priv;
DEBUG(1, "serial_event(0x%06x)\n", event);
switch (event) {
case CS_EVENT_CARD_REMOVAL:
serial_remove(link);
break;
case CS_EVENT_CARD_INSERTION:
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
serial_config(link);
break;
case CS_EVENT_PM_SUSPEND:
serial_suspend(link);
break;
case CS_EVENT_RESET_PHYSICAL:
if ((link->state & DEV_CONFIG) && !info->slave)
pcmcia_release_configuration(link->handle);
break;
case CS_EVENT_PM_RESUME:
serial_resume(link);
break;
case CS_EVENT_CARD_RESET:
if (DEV_OK(link) && !info->slave)
pcmcia_request_configuration(link->handle, &link->conf);
break;
}
return 0;
}
static struct pcmcia_driver serial_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "serial_cs",
},
.attach = serial_attach,
.detach = serial_detach,
};
static int __init init_serial_cs(void)
{
return pcmcia_register_driver(&serial_cs_driver);
}
static void __exit exit_serial_cs(void)
{
pcmcia_unregister_driver(&serial_cs_driver);
/* XXX: this really needs to move into generic code.. */
while (dev_list != NULL)
serial_detach(dev_list);
}
module_init(init_serial_cs);
module_exit(exit_serial_cs);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,711 @@
/* drivers/serial/serial_lh7a40x.c
*
* Copyright (C) 2004 Coastal Environmental Systems
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*/
/* Driver for Sharp LH7A40X embedded serial ports
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
* Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
*
* ---
*
* This driver supports the embedded UARTs of the Sharp LH7A40X series
* CPUs. While similar to the 16550 and other UART chips, there is
* nothing close to register compatibility. Moreover, some of the
* modem control lines are not available, either in the chip or they
* are lacking in the board-level implementation.
*
* - Use of SIRDIS
* For simplicity, we disable the IR functions of any UART whenever
* we enable it.
*
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#define DEV_MAJOR 204
#define DEV_MINOR 16
#define DEV_NR 3
#define ISR_LOOP_LIMIT 256
#define UR(p,o) _UR ((p)->membase, o)
#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
#define UART_REG_SIZE 32
#define UART_R_DATA (0x00)
#define UART_R_FCON (0x04)
#define UART_R_BRCON (0x08)
#define UART_R_CON (0x0c)
#define UART_R_STATUS (0x10)
#define UART_R_RAWISR (0x14)
#define UART_R_INTEN (0x18)
#define UART_R_ISR (0x1c)
#define UARTEN (0x01) /* UART enable */
#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
#define RxEmpty (0x10)
#define TxEmpty (0x80)
#define TxFull (0x20)
#define nRxRdy RxEmpty
#define nTxRdy TxFull
#define TxBusy (0x08)
#define RxBreak (0x0800)
#define RxOverrunError (0x0400)
#define RxParityError (0x0200)
#define RxFramingError (0x0100)
#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
#define DCD (0x04)
#define DSR (0x02)
#define CTS (0x01)
#define RxInt (0x01)
#define TxInt (0x02)
#define ModemInt (0x04)
#define RxTimeoutInt (0x08)
#define MSEOI (0x10)
#define WLEN_8 (0x60)
#define WLEN_7 (0x40)
#define WLEN_6 (0x20)
#define WLEN_5 (0x00)
#define WLEN (0x60) /* Mask for all word-length bits */
#define STP2 (0x08)
#define PEN (0x02) /* Parity Enable */
#define EPS (0x04) /* Even Parity Set */
#define FEN (0x10) /* FIFO Enable */
#define BRK (0x01) /* Send Break */
struct uart_port_lh7a40x {
struct uart_port port;
unsigned int statusPrev; /* Most recently read modem status */
};
static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
{
BIT_CLR (port, UART_R_INTEN, TxInt);
}
static void lh7a40xuart_start_tx (struct uart_port* port,
unsigned int tty_start)
{
BIT_SET (port, UART_R_INTEN, TxInt);
/* *** FIXME: do I need to check for startup of the
transmitter? The old driver did, but AMBA
doesn't . */
}
static void lh7a40xuart_stop_rx (struct uart_port* port)
{
BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
}
static void lh7a40xuart_enable_ms (struct uart_port* port)
{
BIT_SET (port, UART_R_INTEN, ModemInt);
}
static void
#ifdef SUPPORT_SYSRQ
lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
#else
lh7a40xuart_rx_chars (struct uart_port* port)
#endif
{
struct tty_struct* tty = port->info->tty;
int cbRxMax = 256; /* (Gross) limit on receive */
unsigned int data, flag;/* Received data and status */
while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
if (tty->low_latency)
tty_flip_buffer_push(tty);
/*
* If this failed then we will throw away the
* bytes but must do so to clear interrupts
*/
}
data = UR (port, UART_R_DATA);
flag = TTY_NORMAL;
++port->icount.rx;
if (data & RxError) { /* Quick check, short-circuit */
if (data & RxBreak) {
data &= ~(RxFramingError | RxParityError);
++port->icount.brk;
if (uart_handle_break (port))
continue;
}
else if (data & RxParityError)
++port->icount.parity;
else if (data & RxFramingError)
++port->icount.frame;
if (data & RxOverrunError)
++port->icount.overrun;
/* Mask by termios, leave Rx'd byte */
data &= port->read_status_mask | 0xff;
if (data & RxBreak)
flag = TTY_BREAK;
else if (data & RxParityError)
flag = TTY_PARITY;
else if (data & RxFramingError)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
continue;
if ((data & port->ignore_status_mask) == 0) {
tty_insert_flip_char(tty, data, flag);
}
if ((data & RxOverrunError)
&& tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
}
tty_flip_buffer_push (tty);
return;
}
static void lh7a40xuart_tx_chars (struct uart_port* port)
{
struct circ_buf* xmit = &port->info->xmit;
int cbTxMax = port->fifosize;
if (port->x_char) {
UR (port, UART_R_DATA) = port->x_char;
++port->icount.tx;
port->x_char = 0;
return;
}
if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
lh7a40xuart_stop_tx (port, 0);
return;
}
/* Unlike the AMBA UART, the lh7a40x UART does not guarantee
that at least half of the FIFO is empty. Instead, we check
status for every character. Using the AMBA method causes
the transmitter to drop characters. */
do {
UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++port->icount.tx;
if (uart_circ_empty(xmit))
break;
} while (!(UR (port, UART_R_STATUS) & nTxRdy)
&& cbTxMax--);
if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
uart_write_wakeup (port);
if (uart_circ_empty (xmit))
lh7a40xuart_stop_tx (port, 0);
}
static void lh7a40xuart_modem_status (struct uart_port* port)
{
unsigned int status = UR (port, UART_R_STATUS);
unsigned int delta
= status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
if (!delta) /* Only happens if we missed 2 transitions */
return;
((struct uart_port_lh7a40x*) port)->statusPrev = status;
if (delta & DCD)
uart_handle_dcd_change (port, status & DCD);
if (delta & DSR)
++port->icount.dsr;
if (delta & CTS)
uart_handle_cts_change (port, status & CTS);
wake_up_interruptible (&port->info->delta_msr_wait);
}
static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
struct pt_regs* regs)
{
struct uart_port* port = dev_id;
unsigned int cLoopLimit = ISR_LOOP_LIMIT;
unsigned int isr = UR (port, UART_R_ISR);
do {
if (isr & (RxInt | RxTimeoutInt))
#ifdef SUPPORT_SYSRQ
lh7a40xuart_rx_chars(port, regs);
#else
lh7a40xuart_rx_chars(port);
#endif
if (isr & ModemInt)
lh7a40xuart_modem_status (port);
if (isr & TxInt)
lh7a40xuart_tx_chars (port);
if (--cLoopLimit == 0)
break;
isr = UR (port, UART_R_ISR);
} while (isr & (RxInt | TxInt | RxTimeoutInt));
return IRQ_HANDLED;
}
static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
{
return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
}
static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
{
unsigned int result = 0;
unsigned int status = UR (port, UART_R_STATUS);
if (status & DCD)
result |= TIOCM_CAR;
if (status & DSR)
result |= TIOCM_DSR;
if (status & CTS)
result |= TIOCM_CTS;
return result;
}
static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
{
/* None of the ports supports DTR. UART1 supports RTS through GPIO. */
/* Note, kernel appears to be setting DTR and RTS on console. */
/* *** FIXME: this deserves more work. There's some work in
tracing all of the IO pins. */
#if 0
if( port->mapbase == UART1_PHYS) {
gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
if (mctrl & TIOCM_RTS)
gpio->pbdr &= ~GPIOB_UART1_RTS;
else
gpio->pbdr |= GPIOB_UART1_RTS;
}
#endif
}
static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
else
BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
spin_unlock_irqrestore(&port->lock, flags);
}
static int lh7a40xuart_startup (struct uart_port* port)
{
int retval;
retval = request_irq (port->irq, lh7a40xuart_int, 0,
"serial_lh7a40x", port);
if (retval)
return retval;
/* Initial modem control-line settings */
((struct uart_port_lh7a40x*) port)->statusPrev
= UR (port, UART_R_STATUS);
/* There is presently no configuration option to enable IR.
Thus, we always disable it. */
BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
return 0;
}
static void lh7a40xuart_shutdown (struct uart_port* port)
{
free_irq (port->irq, port);
BIT_CLR (port, UART_R_FCON, BRK | FEN);
BIT_CLR (port, UART_R_CON, UARTEN);
}
static void lh7a40xuart_set_termios (struct uart_port* port,
struct termios* termios,
struct termios* old)
{
unsigned int con;
unsigned int inten;
unsigned int fcon;
unsigned long flags;
unsigned int baud;
unsigned int quot;
baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
switch (termios->c_cflag & CSIZE) {
case CS5:
fcon = WLEN_5;
break;
case CS6:
fcon = WLEN_6;
break;
case CS7:
fcon = WLEN_7;
break;
case CS8:
default:
fcon = WLEN_8;
break;
}
if (termios->c_cflag & CSTOPB)
fcon |= STP2;
if (termios->c_cflag & PARENB) {
fcon |= PEN;
if (!(termios->c_cflag & PARODD))
fcon |= EPS;
}
if (port->fifosize > 1)
fcon |= FEN;
spin_lock_irqsave (&port->lock, flags);
uart_update_timeout (port, termios->c_cflag, baud);
port->read_status_mask = RxOverrunError;
if (termios->c_iflag & INPCK)
port->read_status_mask |= RxFramingError | RxParityError;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= RxBreak;
/* Figure mask for status we ignore */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RxFramingError | RxParityError;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= RxBreak;
/* Ignore overrun when ignorning parity */
/* *** FIXME: is this in the right place? */
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= RxOverrunError;
}
/* Ignore all receive errors when receive disabled */
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= RxError;
con = UR (port, UART_R_CON);
inten = (UR (port, UART_R_INTEN) & ~ModemInt);
if (UART_ENABLE_MS (port, termios->c_cflag))
inten |= ModemInt;
BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
UR (port, UART_R_CON) = con; /* Restore UART mode */
spin_unlock_irqrestore(&port->lock, flags);
}
static const char* lh7a40xuart_type (struct uart_port* port)
{
return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
}
static void lh7a40xuart_release_port (struct uart_port* port)
{
release_mem_region (port->mapbase, UART_REG_SIZE);
}
static int lh7a40xuart_request_port (struct uart_port* port)
{
return request_mem_region (port->mapbase, UART_REG_SIZE,
"serial_lh7a40x") != NULL
? 0 : -EBUSY;
}
static void lh7a40xuart_config_port (struct uart_port* port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_LH7A40X;
lh7a40xuart_request_port (port);
}
}
static int lh7a40xuart_verify_port (struct uart_port* port,
struct serial_struct* ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600) /* *** FIXME: is this true? */
ret = -EINVAL;
return ret;
}
static struct uart_ops lh7a40x_uart_ops = {
.tx_empty = lh7a40xuart_tx_empty,
.set_mctrl = lh7a40xuart_set_mctrl,
.get_mctrl = lh7a40xuart_get_mctrl,
.stop_tx = lh7a40xuart_stop_tx,
.start_tx = lh7a40xuart_start_tx,
.stop_rx = lh7a40xuart_stop_rx,
.enable_ms = lh7a40xuart_enable_ms,
.break_ctl = lh7a40xuart_break_ctl,
.startup = lh7a40xuart_startup,
.shutdown = lh7a40xuart_shutdown,
.set_termios = lh7a40xuart_set_termios,
.type = lh7a40xuart_type,
.release_port = lh7a40xuart_release_port,
.request_port = lh7a40xuart_request_port,
.config_port = lh7a40xuart_config_port,
.verify_port = lh7a40xuart_verify_port,
};
static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
{
.port = {
.membase = (void*) io_p2v (UART1_PHYS),
.mapbase = UART1_PHYS,
.iotype = SERIAL_IO_MEM,
.irq = IRQ_UART1INTR,
.uartclk = 14745600/2,
.fifosize = 16,
.ops = &lh7a40x_uart_ops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 0,
},
},
{
.port = {
.membase = (void*) io_p2v (UART2_PHYS),
.mapbase = UART2_PHYS,
.iotype = SERIAL_IO_MEM,
.irq = IRQ_UART2INTR,
.uartclk = 14745600/2,
.fifosize = 16,
.ops = &lh7a40x_uart_ops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 1,
},
},
{
.port = {
.membase = (void*) io_p2v (UART3_PHYS),
.mapbase = UART3_PHYS,
.iotype = SERIAL_IO_MEM,
.irq = IRQ_UART3INTR,
.uartclk = 14745600/2,
.fifosize = 16,
.ops = &lh7a40x_uart_ops,
.flags = ASYNC_BOOT_AUTOCONF,
.line = 2,
},
},
};
#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
# define LH7A40X_CONSOLE NULL
#else
# define LH7A40X_CONSOLE &lh7a40x_console
static void lh7a40xuart_console_write (struct console* co,
const char* s,
unsigned int count)
{
struct uart_port* port = &lh7a40x_ports[co->index].port;
unsigned int con = UR (port, UART_R_CON);
unsigned int inten = UR (port, UART_R_INTEN);
UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
for (; count-- > 0; ++s) {
while (UR (port, UART_R_STATUS) & nTxRdy)
;
UR (port, UART_R_DATA) = *s;
if (*s == '\n') {
while ((UR (port, UART_R_STATUS) & TxBusy))
;
UR (port, UART_R_DATA) = '\r';
}
}
/* Wait until all characters are sent */
while (UR (port, UART_R_STATUS) & TxBusy)
;
/* Restore control and interrupt mask */
UR (port, UART_R_CON) = con;
UR (port, UART_R_INTEN) = inten;
}
static void __init lh7a40xuart_console_get_options (struct uart_port* port,
int* baud,
int* parity,
int* bits)
{
if (UR (port, UART_R_CON) & UARTEN) {
unsigned int fcon = UR (port, UART_R_FCON);
unsigned int quot = UR (port, UART_R_BRCON) + 1;
switch (fcon & (PEN | EPS)) {
default: *parity = 'n'; break;
case PEN: *parity = 'o'; break;
case PEN | EPS: *parity = 'e'; break;
}
switch (fcon & WLEN) {
default:
case WLEN_8: *bits = 8; break;
case WLEN_7: *bits = 7; break;
case WLEN_6: *bits = 6; break;
case WLEN_5: *bits = 5; break;
}
*baud = port->uartclk/(16*quot);
}
}
static int __init lh7a40xuart_console_setup (struct console* co, char* options)
{
struct uart_port* port;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index >= DEV_NR) /* Bounds check on device number */
co->index = 0;
port = &lh7a40x_ports[co->index].port;
if (options)
uart_parse_options (options, &baud, &parity, &bits, &flow);
else
lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
return uart_set_options (port, co, baud, parity, bits, flow);
}
extern struct uart_driver lh7a40x_reg;
static struct console lh7a40x_console = {
.name = "ttyAM",
.write = lh7a40xuart_console_write,
.device = uart_console_device,
.setup = lh7a40xuart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &lh7a40x_reg,
};
static int __init lh7a40xuart_console_init(void)
{
register_console (&lh7a40x_console);
return 0;
}
console_initcall (lh7a40xuart_console_init);
#endif
static struct uart_driver lh7a40x_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyAM",
.dev_name = "ttyAM",
.major = DEV_MAJOR,
.minor = DEV_MINOR,
.nr = DEV_NR,
.cons = LH7A40X_CONSOLE,
};
static int __init lh7a40xuart_init(void)
{
int ret;
printk (KERN_INFO "serial: LH7A40X serial driver\n");
ret = uart_register_driver (&lh7a40x_reg);
if (ret == 0) {
int i;
for (i = 0; i < DEV_NR; i++)
uart_add_one_port (&lh7a40x_reg,
&lh7a40x_ports[i].port);
}
return ret;
}
static void __exit lh7a40xuart_exit(void)
{
int i;
for (i = 0; i < DEV_NR; i++)
uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
uart_unregister_driver (&lh7a40x_reg);
}
module_init (lh7a40xuart_init);
module_exit (lh7a40xuart_exit);
MODULE_AUTHOR ("Marc Singer");
MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
MODULE_LICENSE ("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,573 @@
/* $Id: sh-sci.h,v 1.4 2004/02/19 16:43:56 lethal Exp $
*
* linux/drivers/serial/sh-sci.h
*
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
* Copyright (C) 1999, 2000 Niibe Yutaka
* Copyright (C) 2000 Greg Banks
* Copyright (C) 2002, 2003 Paul Mundt
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
* Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
*/
#include <linux/config.h>
#include <linux/serial_core.h>
#if defined(__H8300H__) || defined(__H8300S__)
#include <asm/gpio.h>
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
#include <asm/regs306x.h>
#endif
#if defined(CONFIG_H8S2678)
#include <asm/regs267x.h>
#endif
#endif
/* Offsets into the sci_port->irqs array */
#define SCIx_ERI_IRQ 0
#define SCIx_RXI_IRQ 1
#define SCIx_TXI_IRQ 2
/* ERI, RXI, TXI, BRI */
#define SCI_IRQS { 23, 24, 25, 0 }
#define SH3_SCIF_IRQS { 56, 57, 59, 58 }
#define SH3_IRDA_IRQS { 52, 53, 55, 54 }
#define SH4_SCIF_IRQS { 40, 41, 43, 42 }
#define STB1_SCIF1_IRQS {23, 24, 26, 25 }
#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
#define SH7300_SCIF0_IRQS {80, 80, 80, 80 }
#define SH73180_SCIF_IRQS {80, 81, 83, 82 }
#define H8300H_SCI_IRQS0 {52, 53, 54, 0 }
#define H8300H_SCI_IRQS1 {56, 57, 58, 0 }
#define H8300H_SCI_IRQS2 {60, 61, 62, 0 }
#define H8S_SCI_IRQS0 {88, 89, 90, 0 }
#define H8S_SCI_IRQS1 {92, 93, 94, 0 }
#define H8S_SCI_IRQS2 {96, 97, 98, 0 }
#define SH5_SCIF_IRQS {39, 40, 42, 0 }
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCI_NPORTS 1
# define SCSPTR 0xffffff7c /* 8 bit */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
# define SCI_NPORTS 3
# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_AND_SCIF
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
# define SCIF0 0xA4400000
# define SCIF2 0xA4410000
# define SCSMR_Ir 0xA44A0000
# define IRDA_SCIF SCIF0
# define SCI_NPORTS 2
# define SCPCR 0xA4000116
# define SCPDR 0xA4000136
/* Set the clock source,
* SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input
* SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output
*/
# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
# define SCIF_ONLY
#elif defined(CONFIG_SH_RTS7751R2D)
# define SCI_NPORTS 1
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
# define SCI_NPORTS 2
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
# define SCI_AND_SCIF
#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
# define SCI_NPORTS 3
# define SCSPTR0 0xfe600000 /* 16 bit SCIF */
# define SCSPTR1 0xfe610000 /* 16 bit SCIF */
# define SCSPTR2 0xfe620000 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
# define SCI_NPORTS 1
# define SCPCR 0xA4050116 /* 16 bit SCIF */
# define SCPDR 0xA4050136 /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
# define SCI_NPORTS 1
# define SCPDR 0xA4050138 /* 16 bit SCIF */
# define SCSPTR2 SCPDR
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
# define SCI_NPORTS 1
# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
# define SCI_NPORTS 2
# define SCSPTR1 0xffe00020 /* 16 bit SCIF */
# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
# include <asm/hardware.h>
# define SCIF_BASE_ADDR 0x01030000
# define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
# define SCIF_PTR2_OFFS 0x0000020
# define SCIF_LSR2_OFFS 0x0000024
# define SCI_NPORTS 1
# define SCI_INIT { \
{ {}, PORT_SCIF, 0, \
SH5_SCIF_IRQS, sci_init_pins_scif } \
}
# define SCSPTR2 ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
# define SCLSR2 ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,
TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
# define SCI_NPORTS 3
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#elif defined(CONFIG_H8S2678)
# define SCI_NPORTS 3
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#else
# error CPU subtype not defined
#endif
/* SCSCR */
#define SCI_CTRL_FLAGS_TIE 0x80 /* all */
#define SCI_CTRL_FLAGS_RIE 0x40 /* all */
#define SCI_CTRL_FLAGS_TE 0x20 /* all */
#define SCI_CTRL_FLAGS_RE 0x10 /* all */
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
#else
#define SCI_CTRL_FLAGS_REIE 0
#endif
/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
/* SCI_CTRL_FLAGS_CKE1 0x02 * all */
/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
/* SCxSR SCI */
#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
/* SCxSR SCIF */
#define SCIF_ER 0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_TEND 0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_TDFE 0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_BRK 0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_FER 0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_PER 0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCIF_ORER 0x0200
#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
#define SCIF_RFDC_MASK 0x007f
#define SCIF_TXROOM_MAX 64
#else
#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
#define SCIF_RFDC_MASK 0x001f
#define SCIF_TXROOM_MAX 16
#endif
#if defined(SCI_ONLY)
# define SCxSR_TEND(port) SCI_TEND
# define SCxSR_ERRORS(port) SCI_ERRORS
# define SCxSR_RDxF(port) SCI_RDRF
# define SCxSR_TDxE(port) SCI_TDRE
# define SCxSR_ORER(port) SCI_ORER
# define SCxSR_FER(port) SCI_FER
# define SCxSR_PER(port) SCI_PER
# define SCxSR_BRK(port) 0x00
# define SCxSR_RDxF_CLEAR(port) 0xbc
# define SCxSR_ERROR_CLEAR(port) 0xc4
# define SCxSR_TDxE_CLEAR(port) 0x78
# define SCxSR_BREAK_CLEAR(port) 0xc4
#elif defined(SCIF_ONLY)
# define SCxSR_TEND(port) SCIF_TEND
# define SCxSR_ERRORS(port) SCIF_ERRORS
# define SCxSR_RDxF(port) SCIF_RDF
# define SCxSR_TDxE(port) SCIF_TDFE
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
# define SCxSR_ORER(port) SCIF_ORER
#else
# define SCxSR_ORER(port) 0x0000
#endif
# define SCxSR_FER(port) SCIF_FER
# define SCxSR_PER(port) SCIF_PER
# define SCxSR_BRK(port) SCIF_BRK
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
# define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc)
# define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73)
# define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf)
# define SCxSR_BREAK_CLEAR(port) (sci_in(port,SCxSR)&0xffe3)
#else
/* SH7705 can also use this, clearing is same between 7705 and 7709 and 7300 */
# define SCxSR_RDxF_CLEAR(port) 0x00fc
# define SCxSR_ERROR_CLEAR(port) 0x0073
# define SCxSR_TDxE_CLEAR(port) 0x00df
# define SCxSR_BREAK_CLEAR(port) 0x00e3
#endif
#else
# define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
# define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
# define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
# define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000)
# define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
# define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
# define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
#endif
/* SCFCR */
#define SCFCR_RFRST 0x0002
#define SCFCR_TFRST 0x0004
#define SCFCR_TCRST 0x4000
#define SCFCR_MCE 0x0008
#define SCI_MAJOR 204
#define SCI_MINOR_START 8
/* Generic serial flags */
#define SCI_RX_THROTTLE 0x0000001
#define SCI_MAGIC 0xbabeface
/*
* Events are used to schedule things to happen at timer-interrupt
* time, instead of at rs interrupt time.
*/
#define SCI_EVENT_WRITE_WAKEUP 0
struct sci_port {
struct uart_port port;
int type;
unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */
void (*init_pins)(struct uart_port *port, unsigned int cflag);
int break_flag;
struct timer_list break_timer;
};
#define SCI_IN(size, offset) \
unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
return ctrl_inb(addr); \
} else { \
return ctrl_inw(addr); \
}
#define SCI_OUT(size, offset, value) \
unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
ctrl_outb(value, addr); \
} else { \
ctrl_outw(value, addr); \
}
#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
static inline unsigned int sci_##name##_in(struct uart_port *port) \
{ \
if (port->type == PORT_SCI) { \
SCI_IN(sci_size, sci_offset) \
} else { \
SCI_IN(scif_size, scif_offset); \
} \
} \
static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
{ \
if (port->type == PORT_SCI) { \
SCI_OUT(sci_size, sci_offset, value) \
} else { \
SCI_OUT(scif_size, scif_offset, value); \
} \
}
#define CPU_SCIF_FNS(name, scif_offset, scif_size) \
static inline unsigned int sci_##name##_in(struct uart_port *port) \
{ \
SCI_IN(scif_size, scif_offset); \
} \
static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
{ \
SCI_OUT(scif_size, scif_offset, value); \
}
#define CPU_SCI_FNS(name, sci_offset, sci_size) \
static inline unsigned int sci_##name##_in(struct uart_port* port) \
{ \
SCI_IN(sci_size, sci_offset); \
} \
static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
{ \
SCI_OUT(sci_size, sci_offset, value); \
}
#ifdef CONFIG_CPU_SH3
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
h8_sci_offset, h8_sci_size) \
CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
#endif
#elif defined(__H8300H__) || defined(__H8300S__)
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
h8_sci_offset, h8_sci_size) \
CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size)
#else
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
h8_sci_offset, h8_sci_size) \
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
SCIF_FNS(SCSCR, 0x08, 16)
SCIF_FNS(SCTDSR, 0x0c, 8)
SCIF_FNS(SCFER, 0x10, 16)
SCIF_FNS(SCxSR, 0x14, 16)
SCIF_FNS(SCFCR, 0x18, 16)
SCIF_FNS(SCFDR, 0x1c, 16)
SCIF_FNS(SCxTDR, 0x20, 8)
SCIF_FNS(SCxRDR, 0x24, 8)
SCIF_FNS(SCLSR, 0x24, 16)
#else
/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/
/* name off sz off sz off sz off sz off sz*/
SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8)
SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8)
SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8)
SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8)
SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8)
SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8)
SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCSPTR, 0, 0, 0x20, 16)
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
#endif
#define sci_in(port, reg) sci_##reg##_in(port)
#define sci_out(port, reg, value) sci_##reg##_out(port, value)
/* H8/300 series SCI pins assignment */
#if defined(__H8300H__) || defined(__H8300S__)
static const struct __attribute__((packed)) {
int port; /* GPIO port no */
unsigned short rx,tx; /* GPIO bit no */
} h8300_sci_pins[] = {
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
{ /* SCI0 */
.port = H8300_GPIO_P9,
.rx = H8300_GPIO_B2,
.tx = H8300_GPIO_B0,
},
{ /* SCI1 */
.port = H8300_GPIO_P9,
.rx = H8300_GPIO_B3,
.tx = H8300_GPIO_B1,
},
{ /* SCI2 */
.port = H8300_GPIO_PB,
.rx = H8300_GPIO_B7,
.tx = H8300_GPIO_B6,
}
#elif defined(CONFIG_H8S2678)
{ /* SCI0 */
.port = H8300_GPIO_P3,
.rx = H8300_GPIO_B2,
.tx = H8300_GPIO_B0,
},
{ /* SCI1 */
.port = H8300_GPIO_P3,
.rx = H8300_GPIO_B3,
.tx = H8300_GPIO_B1,
},
{ /* SCI2 */
.port = H8300_GPIO_P5,
.rx = H8300_GPIO_B1,
.tx = H8300_GPIO_B0,
}
#endif
};
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */
if (port->mapbase == 0xa4000150)
return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xa4000140)
return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == SCIF0)
return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
if (port->mapbase == SCIF2)
return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH4_202)
static inline int sci_rxd_in(struct uart_port *port)
{
#ifndef SCIF_ONLY
if (port->mapbase == 0xffe00000)
return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
#endif
#ifndef SCI_ONLY
if (port->mapbase == 0xffe80000)
return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
#endif
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfe600000)
return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfe610000)
return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xfe620000)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
}
#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xa4430000)
return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
return 1;
}
#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
static inline int sci_rxd_in(struct uart_port *port)
{
return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
}
#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xffe00000)
return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */
else
return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
}
#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
static inline int sci_rxd_in(struct uart_port *port)
{
return sci_in(port, SCSPTR)&0x0001 ? 1 : 0; /* SCIF */
}
#elif defined(__H8300H__) || defined(__H8300S__)
static inline int sci_rxd_in(struct uart_port *port)
{
int ch = (port->mapbase - SMR0) >> 3;
return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
}
#endif
/*
* Values for the BitRate Register (SCBRR)
*
* The values are actually divisors for a frequency which can
* be internal to the SH3 (14.7456MHz) or derived from an external
* clock source. This driver assumes the internal clock is used;
* to support using an external clock source, config options or
* possibly command-line options would need to be added.
*
* Also, to support speeds below 2400 (why?) the lower 2 bits of
* the SCSMR register would also need to be set to non-zero values.
*
* -- Greg Banks 27Feb2000
*
* Answer: The SCBRR register is only eight bits, and the value in
* it gets larger with lower baud rates. At around 2400 (depending on
* the peripherial module clock) you run out of bits. However the
* lower two bits of SCSMR allow the module clock to be divided down,
* scaling the value which is needed in SCBRR.
*
* -- Stuart Menefy - 23 May 2000
*
* I meant, why would anyone bother with bitrates below 2400.
*
* -- Greg Banks - 7Jul2000
*
* You "speedist"! How will I use my 110bps ASR-33 teletype with paper
* tape reader as a console!
*
* -- Mitch Davis - 15 Jul 2000
*/
#define PCLK (current_cpu_data.module_clock)
#if defined(CONFIG_CPU_SUBTYPE_SH7300)
#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(16*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCBRR_VALUE(bps) (((PCLK*2)+16*bps)/(32*bps)-1)
#elif !defined(__H8300H__) && !defined(__H8300S__)
#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(32*bps)-1)
#else
#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
#endif
#define BPS_2400 SCBRR_VALUE(2400)
#define BPS_4800 SCBRR_VALUE(4800)
#define BPS_9600 SCBRR_VALUE(9600)
#define BPS_19200 SCBRR_VALUE(19200)
#define BPS_38400 SCBRR_VALUE(38400)
#define BPS_57600 SCBRR_VALUE(57600)
#define BPS_115200 SCBRR_VALUE(115200)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
/* suncore.c
*
* Common SUN serial routines. Based entirely
* upon drivers/sbus/char/sunserial.c which is:
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*
* Adaptation to new UART layer is:
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/init.h>
#include <asm/oplib.h>
#include "suncore.h"
int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor);
void
sunserial_console_termios(struct console *con)
{
char mode[16], buf[16], *s;
char *mode_prop = "ttyX-mode";
char *cd_prop = "ttyX-ignore-cd";
char *dtr_prop = "ttyX-rts-dtr-off";
int baud, bits, stop, cflag;
char parity;
int carrier = 0;
int rtsdtr = 1;
int topnd, nd;
if (!serial_console)
return;
if (serial_console == 1) {
mode_prop[3] = 'a';
cd_prop[3] = 'a';
dtr_prop[3] = 'a';
} else {
mode_prop[3] = 'b';
cd_prop[3] = 'b';
dtr_prop[3] = 'b';
}
topnd = prom_getchild(prom_root_node);
nd = prom_searchsiblings(topnd, "options");
if (!nd) {
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
if (!prom_node_has_property(nd, mode_prop)) {
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
memset(mode, 0, sizeof(mode));
prom_getstring(nd, mode_prop, mode, sizeof(mode));
if (prom_node_has_property(nd, cd_prop)) {
memset(buf, 0, sizeof(buf));
prom_getstring(nd, cd_prop, buf, sizeof(buf));
if (!strcmp(buf, "false"))
carrier = 1;
/* XXX: this is unused below. */
}
if (prom_node_has_property(nd, dtr_prop)) {
memset(buf, 0, sizeof(buf));
prom_getstring(nd, dtr_prop, buf, sizeof(buf));
if (!strcmp(buf, "false"))
rtsdtr = 0;
/* XXX: this is unused below. */
}
no_options:
cflag = CREAD | HUPCL | CLOCAL;
s = mode;
baud = simple_strtoul(s, NULL, 0);
s = strchr(s, ',');
bits = simple_strtoul(++s, NULL, 0);
s = strchr(s, ',');
parity = *(++s);
s = strchr(s, ',');
stop = simple_strtoul(++s, NULL, 0);
s = strchr(s, ',');
/* XXX handshake is not handled here. */
switch (baud) {
case 150: cflag |= B150; break;
case 300: cflag |= B300; break;
case 600: cflag |= B600; break;
case 1200: cflag |= B1200; break;
case 2400: cflag |= B2400; break;
case 4800: cflag |= B4800; break;
case 9600: cflag |= B9600; break;
case 19200: cflag |= B19200; break;
case 38400: cflag |= B38400; break;
default: baud = 9600; cflag |= B9600; break;
}
switch (bits) {
case 5: cflag |= CS5; break;
case 6: cflag |= CS6; break;
case 7: cflag |= CS7; break;
case 8: cflag |= CS8; break;
default: cflag |= CS8; break;
}
switch (parity) {
case 'o': cflag |= (PARENB | PARODD); break;
case 'e': cflag |= PARENB; break;
case 'n': default: break;
}
switch (stop) {
case 2: cflag |= CSTOPB; break;
case 1: default: break;
}
con->cflag = cflag;
}
EXPORT_SYMBOL(sunserial_console_termios);
/* Sun serial MOUSE auto baud rate detection. */
static struct mouse_baud_cflag {
int baud;
unsigned int cflag;
} mouse_baud_table[] = {
{ 1200, B1200 },
{ 2400, B2400 },
{ 4800, B4800 },
{ 9600, B9600 },
{ -1, ~0 },
{ -1, ~0 },
};
unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud)
{
int i;
for (i = 0; mouse_baud_table[i].baud != -1; i++)
if (mouse_baud_table[i].cflag == (cflag & CBAUD))
break;
i += 1;
if (mouse_baud_table[i].baud == -1)
i = 0;
*new_baud = mouse_baud_table[i].baud;
return mouse_baud_table[i].cflag;
}
EXPORT_SYMBOL(suncore_mouse_baud_cflag_next);
/* Basically, when the baud rate is wrong the mouse spits out
* breaks to us.
*/
int suncore_mouse_baud_detection(unsigned char ch, int is_break)
{
static int mouse_got_break = 0;
static int ctr = 0;
if (is_break) {
/* Let a few normal bytes go by before we jump the gun
* and say we need to try another baud rate.
*/
if (mouse_got_break && ctr < 8)
return 1;
/* Ok, we need to try another baud. */
ctr = 0;
mouse_got_break = 1;
return 2;
}
if (mouse_got_break) {
ctr++;
if (ch == 0x87) {
/* Correct baud rate determined. */
mouse_got_break = 0;
}
return 1;
}
return 0;
}
EXPORT_SYMBOL(suncore_mouse_baud_detection);
static int __init suncore_init(void)
{
return 0;
}
static void __exit suncore_exit(void)
{
}
module_init(suncore_init);
module_exit(suncore_exit);
MODULE_AUTHOR("Eddie C. Dost, David S. Miller");
MODULE_DESCRIPTION("Sun serial common layer");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,29 @@
/* suncore.h
*
* Generic SUN serial/kbd/ms layer. Based entirely
* upon drivers/sbus/char/sunserial.h which is:
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*
* Port to new UART layer is:
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
#ifndef _SERIAL_SUN_H
#define _SERIAL_SUN_H
/* Serial keyboard defines for L1-A processing... */
#define SUNKBD_RESET 0xff
#define SUNKBD_L1 0x01
#define SUNKBD_UP 0x80
#define SUNKBD_A 0x4d
extern unsigned int suncore_mouse_baud_cflag_next(unsigned int, int *);
extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor;
extern void sunserial_console_termios(struct console *);
#endif /* !(_SERIAL_SUN_H) */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,321 @@
/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
#ifndef _SUNSAB_H
#define _SUNSAB_H
struct sab82532_async_rd_regs {
u8 rfifo[0x20]; /* Receive FIFO */
u8 star; /* Status Register */
u8 __pad1;
u8 mode; /* Mode Register */
u8 timr; /* Timer Register */
u8 xon; /* XON Character */
u8 xoff; /* XOFF Character */
u8 tcr; /* Termination Character Register */
u8 dafo; /* Data Format */
u8 rfc; /* RFIFO Control Register */
u8 __pad2;
u8 rbcl; /* Receive Byte Count Low */
u8 rbch; /* Receive Byte Count High */
u8 ccr0; /* Channel Configuration Register 0 */
u8 ccr1; /* Channel Configuration Register 1 */
u8 ccr2; /* Channel Configuration Register 2 */
u8 ccr3; /* Channel Configuration Register 3 */
u8 __pad3[4];
u8 vstr; /* Version Status Register */
u8 __pad4[3];
u8 gis; /* Global Interrupt Status */
u8 ipc; /* Interrupt Port Configuration */
u8 isr0; /* Interrupt Status 0 */
u8 isr1; /* Interrupt Status 1 */
u8 pvr; /* Port Value Register */
u8 pis; /* Port Interrupt Status */
u8 pcr; /* Port Configuration Register */
u8 ccr4; /* Channel Configuration Register 4 */
};
struct sab82532_async_wr_regs {
u8 xfifo[0x20]; /* Transmit FIFO */
u8 cmdr; /* Command Register */
u8 __pad1;
u8 mode;
u8 timr;
u8 xon;
u8 xoff;
u8 tcr;
u8 dafo;
u8 rfc;
u8 __pad2;
u8 xbcl; /* Transmit Byte Count Low */
u8 xbch; /* Transmit Byte Count High */
u8 ccr0;
u8 ccr1;
u8 ccr2;
u8 ccr3;
u8 tsax; /* Time-Slot Assignment Reg. Transmit */
u8 tsar; /* Time-Slot Assignment Reg. Receive */
u8 xccr; /* Transmit Channel Capacity Register */
u8 rccr; /* Receive Channel Capacity Register */
u8 bgr; /* Baud Rate Generator Register */
u8 tic; /* Transmit Immediate Character */
u8 mxn; /* Mask XON Character */
u8 mxf; /* Mask XOFF Character */
u8 iva; /* Interrupt Vector Address */
u8 ipc;
u8 imr0; /* Interrupt Mask Register 0 */
u8 imr1; /* Interrupt Mask Register 1 */
u8 pvr;
u8 pim; /* Port Interrupt Mask */
u8 pcr;
u8 ccr4;
};
struct sab82532_async_rw_regs { /* Read/Write registers */
u8 __pad1[0x20];
u8 __pad2;
u8 __pad3;
u8 mode;
u8 timr;
u8 xon;
u8 xoff;
u8 tcr;
u8 dafo;
u8 rfc;
u8 __pad4;
u8 __pad5;
u8 __pad6;
u8 ccr0;
u8 ccr1;
u8 ccr2;
u8 ccr3;
u8 __pad7;
u8 __pad8;
u8 __pad9;
u8 __pad10;
u8 __pad11;
u8 __pad12;
u8 __pad13;
u8 __pad14;
u8 __pad15;
u8 ipc;
u8 __pad16;
u8 __pad17;
u8 pvr;
u8 __pad18;
u8 pcr;
u8 ccr4;
};
union sab82532_async_regs {
__volatile__ struct sab82532_async_rd_regs r;
__volatile__ struct sab82532_async_wr_regs w;
__volatile__ struct sab82532_async_rw_regs rw;
};
union sab82532_irq_status {
unsigned short stat;
struct {
unsigned char isr0;
unsigned char isr1;
} sreg;
};
/* irqflags bits */
#define SAB82532_ALLS 0x00000001
#define SAB82532_XPR 0x00000002
/* RFIFO Status Byte */
#define SAB82532_RSTAT_PE 0x80
#define SAB82532_RSTAT_FE 0x40
#define SAB82532_RSTAT_PARITY 0x01
/* Status Register (STAR) */
#define SAB82532_STAR_XDOV 0x80
#define SAB82532_STAR_XFW 0x40
#define SAB82532_STAR_RFNE 0x20
#define SAB82532_STAR_FCS 0x10
#define SAB82532_STAR_TEC 0x08
#define SAB82532_STAR_CEC 0x04
#define SAB82532_STAR_CTS 0x02
/* Command Register (CMDR) */
#define SAB82532_CMDR_RMC 0x80
#define SAB82532_CMDR_RRES 0x40
#define SAB82532_CMDR_RFRD 0x20
#define SAB82532_CMDR_STI 0x10
#define SAB82532_CMDR_XF 0x08
#define SAB82532_CMDR_XRES 0x01
/* Mode Register (MODE) */
#define SAB82532_MODE_FRTS 0x40
#define SAB82532_MODE_FCTS 0x20
#define SAB82532_MODE_FLON 0x10
#define SAB82532_MODE_RAC 0x08
#define SAB82532_MODE_RTS 0x04
#define SAB82532_MODE_TRS 0x02
#define SAB82532_MODE_TLP 0x01
/* Timer Register (TIMR) */
#define SAB82532_TIMR_CNT_MASK 0xe0
#define SAB82532_TIMR_VALUE_MASK 0x1f
/* Data Format (DAFO) */
#define SAB82532_DAFO_XBRK 0x40
#define SAB82532_DAFO_STOP 0x20
#define SAB82532_DAFO_PAR_SPACE 0x00
#define SAB82532_DAFO_PAR_ODD 0x08
#define SAB82532_DAFO_PAR_EVEN 0x10
#define SAB82532_DAFO_PAR_MARK 0x18
#define SAB82532_DAFO_PARE 0x04
#define SAB82532_DAFO_CHL8 0x00
#define SAB82532_DAFO_CHL7 0x01
#define SAB82532_DAFO_CHL6 0x02
#define SAB82532_DAFO_CHL5 0x03
/* RFIFO Control Register (RFC) */
#define SAB82532_RFC_DPS 0x40
#define SAB82532_RFC_DXS 0x20
#define SAB82532_RFC_RFDF 0x10
#define SAB82532_RFC_RFTH_1 0x00
#define SAB82532_RFC_RFTH_4 0x04
#define SAB82532_RFC_RFTH_16 0x08
#define SAB82532_RFC_RFTH_32 0x0c
#define SAB82532_RFC_TCDE 0x01
/* Received Byte Count High (RBCH) */
#define SAB82532_RBCH_DMA 0x80
#define SAB82532_RBCH_CAS 0x20
/* Transmit Byte Count High (XBCH) */
#define SAB82532_XBCH_DMA 0x80
#define SAB82532_XBCH_CAS 0x20
#define SAB82532_XBCH_XC 0x10
/* Channel Configuration Register 0 (CCR0) */
#define SAB82532_CCR0_PU 0x80
#define SAB82532_CCR0_MCE 0x40
#define SAB82532_CCR0_SC_NRZ 0x00
#define SAB82532_CCR0_SC_NRZI 0x08
#define SAB82532_CCR0_SC_FM0 0x10
#define SAB82532_CCR0_SC_FM1 0x14
#define SAB82532_CCR0_SC_MANCH 0x18
#define SAB82532_CCR0_SM_HDLC 0x00
#define SAB82532_CCR0_SM_SDLC_LOOP 0x01
#define SAB82532_CCR0_SM_BISYNC 0x02
#define SAB82532_CCR0_SM_ASYNC 0x03
/* Channel Configuration Register 1 (CCR1) */
#define SAB82532_CCR1_ODS 0x10
#define SAB82532_CCR1_BCR 0x08
#define SAB82532_CCR1_CM_MASK 0x07
/* Channel Configuration Register 2 (CCR2) */
#define SAB82532_CCR2_SOC1 0x80
#define SAB82532_CCR2_SOC0 0x40
#define SAB82532_CCR2_BR9 0x80
#define SAB82532_CCR2_BR8 0x40
#define SAB82532_CCR2_BDF 0x20
#define SAB82532_CCR2_SSEL 0x10
#define SAB82532_CCR2_XCS0 0x20
#define SAB82532_CCR2_RCS0 0x10
#define SAB82532_CCR2_TOE 0x08
#define SAB82532_CCR2_RWX 0x04
#define SAB82532_CCR2_DIV 0x01
/* Channel Configuration Register 3 (CCR3) */
#define SAB82532_CCR3_PSD 0x01
/* Time Slot Assignment Register Transmit (TSAX) */
#define SAB82532_TSAX_TSNX_MASK 0xfc
#define SAB82532_TSAX_XCS2 0x02 /* see also CCR2 */
#define SAB82532_TSAX_XCS1 0x01
/* Time Slot Assignment Register Receive (TSAR) */
#define SAB82532_TSAR_TSNR_MASK 0xfc
#define SAB82532_TSAR_RCS2 0x02 /* see also CCR2 */
#define SAB82532_TSAR_RCS1 0x01
/* Version Status Register (VSTR) */
#define SAB82532_VSTR_CD 0x80
#define SAB82532_VSTR_DPLA 0x40
#define SAB82532_VSTR_VN_MASK 0x0f
#define SAB82532_VSTR_VN_1 0x00
#define SAB82532_VSTR_VN_2 0x01
#define SAB82532_VSTR_VN_3_2 0x02
/* Global Interrupt Status Register (GIS) */
#define SAB82532_GIS_PI 0x80
#define SAB82532_GIS_ISA1 0x08
#define SAB82532_GIS_ISA0 0x04
#define SAB82532_GIS_ISB1 0x02
#define SAB82532_GIS_ISB0 0x01
/* Interrupt Vector Address (IVA) */
#define SAB82532_IVA_MASK 0xf1
/* Interrupt Port Configuration (IPC) */
#define SAB82532_IPC_VIS 0x80
#define SAB82532_IPC_SLA1 0x10
#define SAB82532_IPC_SLA0 0x08
#define SAB82532_IPC_CASM 0x04
#define SAB82532_IPC_IC_OPEN_DRAIN 0x00
#define SAB82532_IPC_IC_ACT_LOW 0x01
#define SAB82532_IPC_IC_ACT_HIGH 0x03
/* Interrupt Status Register 0 (ISR0) */
#define SAB82532_ISR0_TCD 0x80
#define SAB82532_ISR0_TIME 0x40
#define SAB82532_ISR0_PERR 0x20
#define SAB82532_ISR0_FERR 0x10
#define SAB82532_ISR0_PLLA 0x08
#define SAB82532_ISR0_CDSC 0x04
#define SAB82532_ISR0_RFO 0x02
#define SAB82532_ISR0_RPF 0x01
/* Interrupt Status Register 1 (ISR1) */
#define SAB82532_ISR1_BRK 0x80
#define SAB82532_ISR1_BRKT 0x40
#define SAB82532_ISR1_ALLS 0x20
#define SAB82532_ISR1_XOFF 0x10
#define SAB82532_ISR1_TIN 0x08
#define SAB82532_ISR1_CSC 0x04
#define SAB82532_ISR1_XON 0x02
#define SAB82532_ISR1_XPR 0x01
/* Interrupt Mask Register 0 (IMR0) */
#define SAB82532_IMR0_TCD 0x80
#define SAB82532_IMR0_TIME 0x40
#define SAB82532_IMR0_PERR 0x20
#define SAB82532_IMR0_FERR 0x10
#define SAB82532_IMR0_PLLA 0x08
#define SAB82532_IMR0_CDSC 0x04
#define SAB82532_IMR0_RFO 0x02
#define SAB82532_IMR0_RPF 0x01
/* Interrupt Mask Register 1 (IMR1) */
#define SAB82532_IMR1_BRK 0x80
#define SAB82532_IMR1_BRKT 0x40
#define SAB82532_IMR1_ALLS 0x20
#define SAB82532_IMR1_XOFF 0x10
#define SAB82532_IMR1_TIN 0x08
#define SAB82532_IMR1_CSC 0x04
#define SAB82532_IMR1_XON 0x02
#define SAB82532_IMR1_XPR 0x01
/* Port Interrupt Status Register (PIS) */
#define SAB82532_PIS_SYNC_B 0x08
#define SAB82532_PIS_DTR_B 0x04
#define SAB82532_PIS_DTR_A 0x02
#define SAB82532_PIS_SYNC_A 0x01
/* Channel Configuration Register 4 (CCR4) */
#define SAB82532_CCR4_MCK4 0x80
#define SAB82532_CCR4_EBRG 0x40
#define SAB82532_CCR4_TST1 0x20
#define SAB82532_CCR4_ICD 0x10
#endif /* !(_SUNSAB_H) */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,272 @@
#ifndef _SUNZILOG_H
#define _SUNZILOG_H
struct zilog_channel {
volatile unsigned char control;
volatile unsigned char __pad1;
volatile unsigned char data;
volatile unsigned char __pad2;
};
struct zilog_layout {
struct zilog_channel channelB;
struct zilog_channel channelA;
};
#define NUM_ZSREGS 16
/* Conversion routines to/from brg time constants from/to bits
* per second.
*/
#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
/* The Zilog register set */
#define FLAG 0x7e
/* Write Register 0 */
#define R0 0 /* Register selects */
#define R1 1
#define R2 2
#define R3 3
#define R4 4
#define R5 5
#define R6 6
#define R7 7
#define R8 8
#define R9 9
#define R10 10
#define R11 11
#define R12 12
#define R13 13
#define R14 14
#define R15 15
#define NULLCODE 0 /* Null Code */
#define POINT_HIGH 0x8 /* Select upper half of registers */
#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
#define SEND_ABORT 0x18 /* HDLC Abort */
#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
#define RES_Tx_P 0x28 /* Reset TxINT Pending */
#define ERR_RES 0x30 /* Error Reset */
#define RES_H_IUS 0x38 /* Reset highest IUS */
#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
#define RES_EOM_L 0xC0 /* Reset EOM latch */
/* Write Register 1 */
#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
#define TxINT_ENAB 0x2 /* Tx Int Enable */
#define PAR_SPEC 0x4 /* Parity is special condition */
#define RxINT_DISAB 0 /* Rx Int Disable */
#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
#define INT_ERR_Rx 0x18 /* Int on error only */
#define RxINT_MASK 0x18
#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
/* Write Register #2 (Interrupt Vector) */
/* Write Register 3 */
#define RxENAB 0x1 /* Rx Enable */
#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
#define ENT_HM 0x10 /* Enter Hunt Mode */
#define AUTO_ENAB 0x20 /* Auto Enables */
#define Rx5 0x0 /* Rx 5 Bits/Character */
#define Rx7 0x40 /* Rx 7 Bits/Character */
#define Rx6 0x80 /* Rx 6 Bits/Character */
#define Rx8 0xc0 /* Rx 8 Bits/Character */
#define RxN_MASK 0xc0
/* Write Register 4 */
#define PAR_ENAB 0x1 /* Parity Enable */
#define PAR_EVEN 0x2 /* Parity Even/Odd* */
#define SYNC_ENAB 0 /* Sync Modes Enable */
#define SB1 0x4 /* 1 stop bit/char */
#define SB15 0x8 /* 1.5 stop bits/char */
#define SB2 0xc /* 2 stop bits/char */
#define MONSYNC 0 /* 8 Bit Sync character */
#define BISYNC 0x10 /* 16 bit sync character */
#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
#define EXTSYNC 0x30 /* External Sync Mode */
#define X1CLK 0x0 /* x1 clock mode */
#define X16CLK 0x40 /* x16 clock mode */
#define X32CLK 0x80 /* x32 clock mode */
#define X64CLK 0xC0 /* x64 clock mode */
#define XCLK_MASK 0xC0
/* Write Register 5 */
#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
#define RTS 0x2 /* RTS */
#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
#define TxENAB 0x8 /* Tx Enable */
#define SND_BRK 0x10 /* Send Break */
#define Tx5 0x0 /* Tx 5 bits (or less)/character */
#define Tx7 0x20 /* Tx 7 bits/character */
#define Tx6 0x40 /* Tx 6 bits/character */
#define Tx8 0x60 /* Tx 8 bits/character */
#define TxN_MASK 0x60
#define DTR 0x80 /* DTR */
/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
/* Write Register 8 (transmit buffer) */
/* Write Register 9 (Master interrupt control) */
#define VIS 1 /* Vector Includes Status */
#define NV 2 /* No Vector */
#define DLC 4 /* Disable Lower Chain */
#define MIE 8 /* Master Interrupt Enable */
#define STATHI 0x10 /* Status high */
#define NORESET 0 /* No reset on write to R9 */
#define CHRB 0x40 /* Reset channel B */
#define CHRA 0x80 /* Reset channel A */
#define FHWRES 0xc0 /* Force hardware reset */
/* Write Register 10 (misc control bits) */
#define BIT6 1 /* 6 bit/8bit sync */
#define LOOPMODE 2 /* SDLC Loop mode */
#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
#define MARKIDLE 8 /* Mark/flag on idle */
#define GAOP 0x10 /* Go active on poll */
#define NRZ 0 /* NRZ mode */
#define NRZI 0x20 /* NRZI mode */
#define FM1 0x40 /* FM1 (transition = 1) */
#define FM0 0x60 /* FM0 (transition = 0) */
#define CRCPS 0x80 /* CRC Preset I/O */
/* Write Register 11 (Clock Mode control) */
#define TRxCXT 0 /* TRxC = Xtal output */
#define TRxCTC 1 /* TRxC = Transmit clock */
#define TRxCBR 2 /* TRxC = BR Generator Output */
#define TRxCDP 3 /* TRxC = DPLL output */
#define TRxCOI 4 /* TRxC O/I */
#define TCRTxCP 0 /* Transmit clock = RTxC pin */
#define TCTRxCP 8 /* Transmit clock = TRxC pin */
#define TCBR 0x10 /* Transmit clock = BR Generator output */
#define TCDPLL 0x18 /* Transmit clock = DPLL output */
#define RCRTxCP 0 /* Receive clock = RTxC pin */
#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
#define RCBR 0x40 /* Receive clock = BR Generator output */
#define RCDPLL 0x60 /* Receive clock = DPLL output */
#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
/* Write Register 12 (lower byte of baud rate generator time constant) */
/* Write Register 13 (upper byte of baud rate generator time constant) */
/* Write Register 14 (Misc control bits) */
#define BRENAB 1 /* Baud rate generator enable */
#define BRSRC 2 /* Baud rate generator source */
#define DTRREQ 4 /* DTR/Request function */
#define AUTOECHO 8 /* Auto Echo */
#define LOOPBAK 0x10 /* Local loopback */
#define SEARCH 0x20 /* Enter search mode */
#define RMC 0x40 /* Reset missing clock */
#define DISDPLL 0x60 /* Disable DPLL */
#define SSBR 0x80 /* Set DPLL source = BR generator */
#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
#define SFMM 0xc0 /* Set FM mode */
#define SNRZI 0xe0 /* Set NRZI mode */
/* Write Register 15 (external/status interrupt control) */
#define ZCIE 2 /* Zero count IE */
#define DCDIE 8 /* DCD IE */
#define SYNCIE 0x10 /* Sync/hunt IE */
#define CTSIE 0x20 /* CTS IE */
#define TxUIE 0x40 /* Tx Underrun/EOM IE */
#define BRKIE 0x80 /* Break/Abort IE */
/* Read Register 0 */
#define Rx_CH_AV 0x1 /* Rx Character Available */
#define ZCOUNT 0x2 /* Zero count */
#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
#define DCD 0x8 /* DCD */
#define SYNC 0x10 /* Sync/hunt */
#define CTS 0x20 /* CTS */
#define TxEOM 0x40 /* Tx underrun */
#define BRK_ABRT 0x80 /* Break/Abort */
/* Read Register 1 */
#define ALL_SNT 0x1 /* All sent */
/* Residue Data for 8 Rx bits/char programmed */
#define RES3 0x8 /* 0/3 */
#define RES4 0x4 /* 0/4 */
#define RES5 0xc /* 0/5 */
#define RES6 0x2 /* 0/6 */
#define RES7 0xa /* 0/7 */
#define RES8 0x6 /* 0/8 */
#define RES18 0xe /* 1/8 */
#define RES28 0x0 /* 2/8 */
/* Special Rx Condition Interrupts */
#define PAR_ERR 0x10 /* Parity error */
#define Rx_OVR 0x20 /* Rx Overrun Error */
#define CRC_ERR 0x40 /* CRC/Framing Error */
#define END_FR 0x80 /* End of Frame (SDLC) */
/* Read Register 2 (channel b only) - Interrupt vector */
#define CHB_Tx_EMPTY 0x00
#define CHB_EXT_STAT 0x02
#define CHB_Rx_AVAIL 0x04
#define CHB_SPECIAL 0x06
#define CHA_Tx_EMPTY 0x08
#define CHA_EXT_STAT 0x0a
#define CHA_Rx_AVAIL 0x0c
#define CHA_SPECIAL 0x0e
#define STATUS_MASK 0x0e
/* Read Register 3 (interrupt pending register) ch a only */
#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
#define CHBTxIP 0x2 /* Channel B Tx IP */
#define CHBRxIP 0x4 /* Channel B Rx IP */
#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
#define CHATxIP 0x10 /* Channel A Tx IP */
#define CHARxIP 0x20 /* Channel A Rx IP */
/* Read Register 8 (receive data register) */
/* Read Register 10 (misc status bits) */
#define ONLOOP 2 /* On loop */
#define LOOPSEND 0x10 /* Loop sending */
#define CLK2MIS 0x40 /* Two clocks missing */
#define CLK1MIS 0x80 /* One clock missing */
/* Read Register 12 (lower byte of baud rate generator constant) */
/* Read Register 13 (upper byte of baud rate generator constant) */
/* Read Register 15 (value of WR 15) */
/* Misc macros */
#define ZS_CLEARERR(channel) do { sbus_writeb(ERR_RES, &channel->control); \
udelay(5); } while(0)
#define ZS_CLEARSTAT(channel) do { sbus_writeb(RES_EXT_INT, &channel->control); \
udelay(5); } while(0)
#define ZS_CLEARFIFO(channel) do { sbus_readb(&channel->data); \
udelay(2); \
sbus_readb(&channel->data); \
udelay(2); \
sbus_readb(&channel->data); \
udelay(2); } while(0)
#endif /* _SUNZILOG_H */

View File

@@ -0,0 +1,782 @@
/*
* linux/drivers/serial/uart00.c
*
* Driver for UART00 serial ports
*
* Based on drivers/char/serial_amba.c, by ARM Limited &
* Deep Blue Solutions Ltd.
* Copyright 2001 Altera Corporation
*
* Update for 2.6.4 by Dirk Behme <dirk.behme@de.bosch.com>
*
* 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
*
* $Id: uart00.c,v 1.35 2002/07/28 10:03:28 rmk Exp $
*
*/
#include <linux/config.h>
#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/sizes.h>
#include <asm/arch/excalibur.h>
#define UART00_TYPE (volatile unsigned int*)
#include <asm/arch/uart00.h>
#include <asm/arch/int_ctrl00.h>
#define UART_NR 2
#define SERIAL_UART00_NAME "ttyUA"
#define SERIAL_UART00_MAJOR 204
#define SERIAL_UART00_MINOR 16 /* Temporary - will change in future */
#define SERIAL_UART00_NR UART_NR
#define UART_PORT_SIZE 0x50
#define UART00_ISR_PASS_LIMIT 256
/*
* Access macros for the UART00 UARTs
*/
#define UART_GET_INT_STATUS(p) inl(UART_ISR((p)->membase))
#define UART_PUT_IES(p, c) outl(c,UART_IES((p)->membase))
#define UART_GET_IES(p) inl(UART_IES((p)->membase))
#define UART_PUT_IEC(p, c) outl(c,UART_IEC((p)->membase))
#define UART_GET_IEC(p) inl(UART_IEC((p)->membase))
#define UART_PUT_CHAR(p, c) outl(c,UART_TD((p)->membase))
#define UART_GET_CHAR(p) inl(UART_RD((p)->membase))
#define UART_GET_RSR(p) inl(UART_RSR((p)->membase))
#define UART_GET_RDS(p) inl(UART_RDS((p)->membase))
#define UART_GET_MSR(p) inl(UART_MSR((p)->membase))
#define UART_GET_MCR(p) inl(UART_MCR((p)->membase))
#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase))
#define UART_GET_MC(p) inl(UART_MC((p)->membase))
#define UART_PUT_MC(p, c) outl(c,UART_MC((p)->membase))
#define UART_GET_TSR(p) inl(UART_TSR((p)->membase))
#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase))
#define UART_PUT_DIV_HI(p,c) outl(c,UART_DIV_HI((p)->membase))
#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase))
#define UART_PUT_DIV_LO(p,c) outl(c,UART_DIV_LO((p)->membase))
#define UART_RX_DATA(s) ((s) & UART_RSR_RX_LEVEL_MSK)
#define UART_TX_READY(s) (((s) & UART_TSR_TX_LEVEL_MSK) < 15)
//#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0)
static void uart00_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
UART_PUT_IEC(port, UART_IEC_TIE_MSK);
}
static void uart00_stop_rx(struct uart_port *port)
{
UART_PUT_IEC(port, UART_IEC_RE_MSK);
}
static void uart00_enable_ms(struct uart_port *port)
{
UART_PUT_IES(port, UART_IES_ME_MSK);
}
static void
uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
{
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, rds, flg, ignored = 0;
status = UART_GET_RSR(port);
while (UART_RX_DATA(status)) {
/*
* We need to read rds before reading the
* character from the fifo
*/
rds = UART_GET_RDS(port);
ch = UART_GET_CHAR(port);
port->icount.rx++;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
goto ignore_char;
flg = TTY_NORMAL;
/*
* Note that the error handling code is
* out of the main execution path
*/
if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK|
UART_RDS_PE_MSK |UART_RDS_PE_MSK))
goto handle_error;
if (uart_handle_sysrq_char(port, ch, regs))
goto ignore_char;
error_return:
tty_insert_flip_char(tty, ch, flg);
ignore_char:
status = UART_GET_RSR(port);
}
out:
tty_flip_buffer_push(tty);
return;
handle_error:
if (rds & UART_RDS_BI_MSK) {
status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK);
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
} else if (rds & UART_RDS_PE_MSK)
port->icount.parity++;
else if (rds & UART_RDS_FE_MSK)
port->icount.frame++;
if (rds & UART_RDS_OE_MSK)
port->icount.overrun++;
if (rds & port->ignore_status_mask) {
if (++ignored > 100)
goto out;
goto ignore_char;
}
rds &= port->read_status_mask;
if (rds & UART_RDS_BI_MSK)
flg = TTY_BREAK;
else if (rds & UART_RDS_PE_MSK)
flg = TTY_PARITY;
else if (rds & UART_RDS_FE_MSK)
flg = TTY_FRAME;
if (rds & UART_RDS_OE_MSK) {
/*
* CHECK: does overrun affect the current character?
* ASSUMPTION: it does not.
*/
tty_insert_flip_char(tty, ch, flg);
ch = 0;
flg = TTY_OVERRUN;
}
#ifdef SUPPORT_SYSRQ
port->sysrq = 0;
#endif
goto error_return;
}
static void uart00_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
int count;
if (port->x_char) {
while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15)
barrier();
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
uart00_stop_tx(port, 0);
return;
}
count = port->fifosize >> 1;
do {
while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15)
barrier();
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
uart00_stop_tx(port, 0);
}
static void uart00_start_tx(struct uart_port *port, unsigned int tty_start)
{
UART_PUT_IES(port, UART_IES_TIE_MSK);
uart00_tx_chars(port);
}
static void uart00_modem_status(struct uart_port *port)
{
unsigned int status;
status = UART_GET_MSR(port);
if (!(status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK |
UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)))
return;
if (status & UART_MSR_DDCD_MSK)
uart_handle_dcd_change(port, status & UART_MSR_DCD_MSK);
if (status & UART_MSR_DDSR_MSK)
port->icount.dsr++;
if (status & UART_MSR_DCTS_MSK)
uart_handle_cts_change(port, status & UART_MSR_CTS_MSK);
wake_up_interruptible(&port->info->delta_msr_wait);
}
static irqreturn_t uart00_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_port *port = dev_id;
unsigned int status, pass_counter = 0;
status = UART_GET_INT_STATUS(port);
do {
if (status & UART_ISR_RI_MSK)
uart00_rx_chars(port, regs);
if (status & UART_ISR_MI_MSK)
uart00_modem_status(port);
if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK))
uart00_tx_chars(port);
if (pass_counter++ > UART00_ISR_PASS_LIMIT)
break;
status = UART_GET_INT_STATUS(port);
} while (status);
return IRQ_HANDLED;
}
static unsigned int uart00_tx_empty(struct uart_port *port)
{
return UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK? 0 : TIOCSER_TEMT;
}
static unsigned int uart00_get_mctrl(struct uart_port *port)
{
unsigned int result = 0;
unsigned int status;
status = UART_GET_MSR(port);
if (status & UART_MSR_DCD_MSK)
result |= TIOCM_CAR;
if (status & UART_MSR_DSR_MSK)
result |= TIOCM_DSR;
if (status & UART_MSR_CTS_MSK)
result |= TIOCM_CTS;
if (status & UART_MSR_RI_MSK)
result |= TIOCM_RI;
return result;
}
static void uart00_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
{
}
static void uart00_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int mcr;
spin_lock_irqsave(&port->lock, flags);
mcr = UART_GET_MCR(port);
if (break_state == -1)
mcr |= UART_MCR_BR_MSK;
else
mcr &= ~UART_MCR_BR_MSK;
UART_PUT_MCR(port, mcr);
spin_unlock_irqrestore(&port->lock, flags);
}
static void
uart00_set_termios(struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned int uart_mc, old_ies, baud, quot;
unsigned long flags;
/*
* We don't support CREAD (yet)
*/
termios->c_cflag |= CREAD;
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
/* byte size and parity */
switch (termios->c_cflag & CSIZE) {
case CS5:
uart_mc = UART_MC_CLS_CHARLEN_5;
break;
case CS6:
uart_mc = UART_MC_CLS_CHARLEN_6;
break;
case CS7:
uart_mc = UART_MC_CLS_CHARLEN_7;
break;
default: // CS8
uart_mc = UART_MC_CLS_CHARLEN_8;
break;
}
if (termios->c_cflag & CSTOPB)
uart_mc|= UART_MC_ST_TWO;
if (termios->c_cflag & PARENB) {
uart_mc |= UART_MC_PE_MSK;
if (!(termios->c_cflag & PARODD))
uart_mc |= UART_MC_EP_MSK;
}
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UART_RDS_OE_MSK;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= UART_RDS_BI_MSK;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= UART_RDS_BI_MSK;
/*
* If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_RDS_OE_MSK;
}
/* first, disable everything */
old_ies = UART_GET_IES(port);
if (UART_ENABLE_MS(port, termios->c_cflag))
old_ies |= UART_IES_ME_MSK;
/* Set baud rate */
UART_PUT_DIV_LO(port, (quot & 0xff));
UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
UART_PUT_MC(port, uart_mc);
UART_PUT_IES(port, old_ies);
spin_unlock_irqrestore(&port->lock, flags);
}
static int uart00_startup(struct uart_port *port)
{
int result;
/*
* Allocate the IRQ
*/
result = request_irq(port->irq, uart00_int, 0, "uart00", port);
if (result) {
printk(KERN_ERR "Request of irq %d failed\n", port->irq);
return result;
}
/*
* Finally, enable interrupts. Use the TII interrupt to minimise
* the number of interrupts generated. If higher performance is
* needed, consider using the TI interrupt with a suitable FIFO
* threshold
*/
UART_PUT_IES(port, UART_IES_RE_MSK | UART_IES_TIE_MSK);
return 0;
}
static void uart00_shutdown(struct uart_port *port)
{
/*
* disable all interrupts, disable the port
*/
UART_PUT_IEC(port, 0xff);
/* disable break condition and fifos */
UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK);
/*
* Free the interrupt
*/
free_irq(port->irq, port);
}
static const char *uart00_type(struct uart_port *port)
{
return port->type == PORT_UART00 ? "Altera UART00" : NULL;
}
/*
* Release the memory region(s) being used by 'port'
*/
static void uart00_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, UART_PORT_SIZE);
#ifdef CONFIG_ARCH_CAMELOT
if (port->membase != (void*)IO_ADDRESS(EXC_UART00_BASE)) {
iounmap(port->membase);
}
#endif
}
/*
* Request the memory region(s) being used by 'port'
*/
static int uart00_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_uart00")
!= NULL ? 0 : -EBUSY;
}
/*
* Configure/autoconfigure the port.
*/
static void uart00_config_port(struct uart_port *port, int flags)
{
/*
* Map the io memory if this is a soft uart
*/
if (!port->membase)
port->membase = ioremap_nocache(port->mapbase,SZ_4K);
if (!port->membase)
printk(KERN_ERR "serial00: cannot map io memory\n");
else
port->type = PORT_UART00;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int uart00_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
static struct uart_ops uart00_pops = {
.tx_empty = uart00_tx_empty,
.set_mctrl = uart00_set_mctrl_null,
.get_mctrl = uart00_get_mctrl,
.stop_tx = uart00_stop_tx,
.start_tx = uart00_start_tx,
.stop_rx = uart00_stop_rx,
.enable_ms = uart00_enable_ms,
.break_ctl = uart00_break_ctl,
.startup = uart00_startup,
.shutdown = uart00_shutdown,
.set_termios = uart00_set_termios,
.type = uart00_type,
.release_port = uart00_release_port,
.request_port = uart00_request_port,
.config_port = uart00_config_port,
.verify_port = uart00_verify_port,
};
#ifdef CONFIG_ARCH_CAMELOT
static struct uart_port epxa10db_port = {
.membase = (void*)IO_ADDRESS(EXC_UART00_BASE),
.mapbase = EXC_UART00_BASE,
.iotype = SERIAL_IO_MEM,
.irq = IRQ_UART,
.uartclk = EXC_AHB2_CLK_FREQUENCY,
.fifosize = 16,
.ops = &uart00_pops,
.flags = ASYNC_BOOT_AUTOCONF,
};
#endif
#ifdef CONFIG_SERIAL_UART00_CONSOLE
static void uart00_console_write(struct console *co, const char *s, unsigned count)
{
#ifdef CONFIG_ARCH_CAMELOT
struct uart_port *port = &epxa10db_port;
unsigned int status, old_ies;
int i;
/*
* First save the CR then disable the interrupts
*/
old_ies = UART_GET_IES(port);
UART_PUT_IEC(port,0xff);
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
do {
status = UART_GET_TSR(port);
} while (!UART_TX_READY(status));
UART_PUT_CHAR(port, s[i]);
if (s[i] == '\n') {
do {
status = UART_GET_TSR(port);
} while (!UART_TX_READY(status));
UART_PUT_CHAR(port, '\r');
}
}
/*
* Finally, wait for transmitter to become empty
* and restore the IES
*/
do {
status = UART_GET_TSR(port);
} while (status & UART_TSR_TX_LEVEL_MSK);
UART_PUT_IES(port, old_ies);
#endif
}
static void __init
uart00_console_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
unsigned int uart_mc, quot;
uart_mc = UART_GET_MC(port);
*parity = 'n';
if (uart_mc & UART_MC_PE_MSK) {
if (uart_mc & UART_MC_EP_MSK)
*parity = 'e';
else
*parity = 'o';
}
switch (uart_mc & UART_MC_CLS_MSK) {
case UART_MC_CLS_CHARLEN_5:
*bits = 5;
break;
case UART_MC_CLS_CHARLEN_6:
*bits = 6;
break;
case UART_MC_CLS_CHARLEN_7:
*bits = 7;
break;
case UART_MC_CLS_CHARLEN_8:
*bits = 8;
break;
}
quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
*baud = port->uartclk / (16 *quot );
}
static int __init uart00_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
#ifdef CONFIG_ARCH_CAMELOT
port = &epxa10db_port; ;
#else
return -ENODEV;
#endif
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
uart00_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
extern struct uart_driver uart00_reg;
static struct console uart00_console = {
.name = SERIAL_UART00_NAME,
.write = uart00_console_write,
.device = uart_console_device,
.setup = uart00_console_setup,
.flags = CON_PRINTBUFFER,
.index = 0,
.data = &uart00_reg,
};
static int __init uart00_console_init(void)
{
register_console(&uart00_console);
return 0;
}
console_initcall(uart00_console_init);
#define UART00_CONSOLE &uart00_console
#else
#define UART00_CONSOLE NULL
#endif
static struct uart_driver uart00_reg = {
.owner = NULL,
.driver_name = SERIAL_UART00_NAME,
.dev_name = SERIAL_UART00_NAME,
.major = SERIAL_UART00_MAJOR,
.minor = SERIAL_UART00_MINOR,
.nr = UART_NR,
.cons = UART00_CONSOLE,
};
struct dev_port_entry{
unsigned int base_addr;
struct uart_port *port;
};
#ifdef CONFIG_PLD_HOTSWAP
static struct dev_port_entry dev_port_map[UART_NR];
/*
* Keep a mapping of dev_info addresses -> port lines to use when
* removing ports dev==NULL indicates unused entry
*/
struct uart00_ps_data{
unsigned int clk;
unsigned int fifosize;
};
int uart00_add_device(struct pldhs_dev_info* dev_info, void* dev_ps_data)
{
struct uart00_ps_data* dev_ps=dev_ps_data;
struct uart_port * port;
int i,result;
i=0;
while(dev_port_map[i].port)
i++;
if(i==UART_NR){
printk(KERN_WARNING "uart00: Maximum number of ports reached\n");
return 0;
}
port=kmalloc(sizeof(struct uart_port),GFP_KERNEL);
if(!port)
return -ENOMEM;
printk("clk=%d fifo=%d\n",dev_ps->clk,dev_ps->fifosize);
port->membase=0;
port->mapbase=dev_info->base_addr;
port->iotype=SERIAL_IO_MEM;
port->irq=dev_info->irq;
port->uartclk=dev_ps->clk;
port->fifosize=dev_ps->fifosize;
port->ops=&uart00_pops;
port->line=i;
port->flags=ASYNC_BOOT_AUTOCONF;
result=uart_add_one_port(&uart00_reg, port);
if(result){
printk("uart_add_one_port returned %d\n",result);
return result;
}
dev_port_map[i].base_addr=dev_info->base_addr;
dev_port_map[i].port=port;
printk("uart00: added device at %x as ttyUA%d\n",dev_port_map[i].base_addr,i);
return 0;
}
int uart00_remove_devices(void)
{
int i,result;
result=0;
for(i=1;i<UART_NR;i++){
if(dev_port_map[i].base_addr){
result=uart_remove_one_port(&uart00_reg, dev_port_map[i].port);
if(result)
return result;
/* port removed sucessfully, so now tidy up */
kfree(dev_port_map[i].port);
dev_port_map[i].base_addr=0;
dev_port_map[i].port=NULL;
}
}
return 0;
}
struct pld_hotswap_ops uart00_pldhs_ops={
.name = "uart00",
.add_device = uart00_add_device,
.remove_devices = uart00_remove_devices,
};
#endif
static int __init uart00_init(void)
{
int result;
printk(KERN_INFO "Serial: UART00 driver $Revision: 1.35 $\n");
printk(KERN_WARNING "serial_uart00:Using temporary major/minor pairs"
" - these WILL change in the future\n");
result = uart_register_driver(&uart00_reg);
if (result)
return result;
#ifdef CONFIG_ARCH_CAMELOT
result = uart_add_one_port(&uart00_reg,&epxa10db_port);
#endif
if (result)
uart_unregister_driver(&uart00_reg);
#ifdef CONFIG_PLD_HOTSWAP
pldhs_register_driver(&uart00_pldhs_ops);
#endif
return result;
}
__initcall(uart00_init);

View File

@@ -0,0 +1,549 @@
/*
* drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB
*
* Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
* Written by Miles Bader <miles@gnu.org>
*/
/* This driver supports both the original V850E UART interface (called
merely `UART' in the docs) and the newer `UARTB' interface, which is
roughly a superset of the first one. The selection is made at
configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is
presumed, otherwise the old UART -- as these are on-CPU UARTS, a system
can never have both.
The UARTB interface also has a 16-entry FIFO mode, which is not
yet supported by this driver. */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <asm/v850e_uart.h>
/* Initial UART state. This may be overridden by machine-dependent headers. */
#ifndef V850E_UART_INIT_BAUD
#define V850E_UART_INIT_BAUD 115200
#endif
#ifndef V850E_UART_INIT_CFLAGS
#define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD)
#endif
/* A string used for prefixing printed descriptions; since the same UART
macro is actually used on other chips than the V850E. This must be a
constant string. */
#ifndef V850E_UART_CHIP_NAME
#define V850E_UART_CHIP_NAME "V850E"
#endif
#define V850E_UART_MINOR_BASE 64 /* First tty minor number */
/* Low-level UART functions. */
/* Configure and turn on uart channel CHAN, using the termios `control
modes' bits in CFLAGS, and a baud-rate of BAUD. */
void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud)
{
int flags;
v850e_uart_speed_t old_speed;
v850e_uart_config_t old_config;
v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud);
v850e_uart_config_t new_config = v850e_uart_calc_config (cflags);
/* Disable interrupts while we're twiddling the hardware. */
local_irq_save (flags);
#ifdef V850E_UART_PRE_CONFIGURE
V850E_UART_PRE_CONFIGURE (chan, cflags, baud);
#endif
old_config = V850E_UART_CONFIG (chan);
old_speed = v850e_uart_speed (chan);
if (! v850e_uart_speed_eq (old_speed, new_speed)) {
/* The baud rate has changed. First, disable the UART. */
V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI;
old_config = 0; /* Force the uart to be re-initialized. */
/* Reprogram the baud-rate generator. */
v850e_uart_set_speed (chan, new_speed);
}
if (! (old_config & V850E_UART_CONFIG_ENABLED)) {
/* If we are using the uart for the first time, start by
enabling it, which must be done before turning on any
other bits. */
V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT;
/* See the initial state. */
old_config = V850E_UART_CONFIG (chan);
}
if (new_config != old_config) {
/* Which of the TXE/RXE bits we'll temporarily turn off
before changing other control bits. */
unsigned temp_disable = 0;
/* Which of the TXE/RXE bits will be enabled. */
unsigned enable = 0;
unsigned changed_bits = new_config ^ old_config;
/* Which of RX/TX will be enabled in the new configuration. */
if (new_config & V850E_UART_CONFIG_RX_BITS)
enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE);
if (new_config & V850E_UART_CONFIG_TX_BITS)
enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE);
/* Figure out which of RX/TX needs to be disabled; note
that this will only happen if they're not already
disabled. */
if (changed_bits & V850E_UART_CONFIG_RX_BITS)
temp_disable
|= (old_config & V850E_UART_CONFIG_RX_ENABLE);
if (changed_bits & V850E_UART_CONFIG_TX_BITS)
temp_disable
|= (old_config & V850E_UART_CONFIG_TX_ENABLE);
/* We have to turn off RX and/or TX mode before changing
any associated control bits. */
if (temp_disable)
V850E_UART_CONFIG (chan) = old_config & ~temp_disable;
/* Write the new control bits, while RX/TX are disabled. */
if (changed_bits & ~enable)
V850E_UART_CONFIG (chan) = new_config & ~enable;
v850e_uart_config_delay (new_config, new_speed);
/* Write the final version, with enable bits turned on. */
V850E_UART_CONFIG (chan) = new_config;
}
local_irq_restore (flags);
}
/* Low-level console. */
#ifdef CONFIG_V850E_UART_CONSOLE
static void v850e_uart_cons_write (struct console *co,
const char *s, unsigned count)
{
if (count > 0) {
unsigned chan = co->index;
unsigned irq = V850E_UART_TX_IRQ (chan);
int irq_was_enabled, irq_was_pending, flags;
/* We don't want to get `transmission completed'
interrupts, since we're busy-waiting, so we disable them
while sending (we don't disable interrupts entirely
because sending over a serial line is really slow). We
save the status of the tx interrupt and restore it when
we're done so that using printk doesn't interfere with
normal serial transmission (other than interleaving the
output, of course!). This should work correctly even if
this function is interrupted and the interrupt printks
something. */
/* Disable interrupts while fiddling with tx interrupt. */
local_irq_save (flags);
/* Get current tx interrupt status. */
irq_was_enabled = v850e_intc_irq_enabled (irq);
irq_was_pending = v850e_intc_irq_pending (irq);
/* Disable tx interrupt if necessary. */
if (irq_was_enabled)
v850e_intc_disable_irq (irq);
/* Turn interrupts back on. */
local_irq_restore (flags);
/* Send characters. */
while (count > 0) {
int ch = *s++;
if (ch == '\n') {
/* We don't have the benefit of a tty
driver, so translate NL into CR LF. */
v850e_uart_wait_for_xmit_ok (chan);
v850e_uart_putc (chan, '\r');
}
v850e_uart_wait_for_xmit_ok (chan);
v850e_uart_putc (chan, ch);
count--;
}
/* Restore saved tx interrupt status. */
if (irq_was_enabled) {
/* Wait for the last character we sent to be
completely transmitted (as we'll get an
interrupt interrupt at that point). */
v850e_uart_wait_for_xmit_done (chan);
/* Clear pending interrupts received due
to our transmission, unless there was already
one pending, in which case we want the
handler to be called. */
if (! irq_was_pending)
v850e_intc_clear_pending_irq (irq);
/* ... and then turn back on handling. */
v850e_intc_enable_irq (irq);
}
}
}
extern struct uart_driver v850e_uart_driver;
static struct console v850e_uart_cons =
{
.name = "ttyS",
.write = v850e_uart_cons_write,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.cflag = V850E_UART_INIT_CFLAGS,
.index = -1,
.data = &v850e_uart_driver,
};
void v850e_uart_cons_init (unsigned chan)
{
v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS,
V850E_UART_INIT_BAUD);
v850e_uart_cons.index = chan;
register_console (&v850e_uart_cons);
printk ("Console: %s on-chip UART channel %d\n",
V850E_UART_CHIP_NAME, chan);
}
/* This is what the init code actually calls. */
static int v850e_uart_console_init (void)
{
v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL);
return 0;
}
console_initcall(v850e_uart_console_init);
#define V850E_UART_CONSOLE &v850e_uart_cons
#else /* !CONFIG_V850E_UART_CONSOLE */
#define V850E_UART_CONSOLE 0
#endif /* CONFIG_V850E_UART_CONSOLE */
/* TX/RX interrupt handlers. */
static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop);
void v850e_uart_tx (struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
int stopped = uart_tx_stopped (port);
if (v850e_uart_xmit_ok (port->line)) {
int tx_ch;
if (port->x_char) {
tx_ch = port->x_char;
port->x_char = 0;
} else if (!uart_circ_empty (xmit) && !stopped) {
tx_ch = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
} else
goto no_xmit;
v850e_uart_putc (port->line, tx_ch);
port->icount.tx++;
if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
uart_write_wakeup (port);
}
no_xmit:
if (uart_circ_empty (xmit) || stopped)
v850e_uart_stop_tx (port, stopped);
}
static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs)
{
struct uart_port *port = data;
v850e_uart_tx (port);
return IRQ_HANDLED;
}
static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs)
{
struct uart_port *port = data;
unsigned ch_stat = TTY_NORMAL;
unsigned ch = v850e_uart_getc (port->line);
unsigned err = v850e_uart_err (port->line);
if (err) {
if (err & V850E_UART_ERR_OVERRUN) {
ch_stat = TTY_OVERRUN;
port->icount.overrun++;
} else if (err & V850E_UART_ERR_FRAME) {
ch_stat = TTY_FRAME;
port->icount.frame++;
} else if (err & V850E_UART_ERR_PARITY) {
ch_stat = TTY_PARITY;
port->icount.parity++;
}
}
port->icount.rx++;
tty_insert_flip_char (port->info->tty, ch, ch_stat);
tty_schedule_flip (port->info->tty);
return IRQ_HANDLED;
}
/* Control functions for the serial framework. */
static void v850e_uart_nop (struct uart_port *port) { }
static int v850e_uart_success (struct uart_port *port) { return 0; }
static unsigned v850e_uart_tx_empty (struct uart_port *port)
{
return TIOCSER_TEMT; /* Can't detect. */
}
static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl)
{
#ifdef V850E_UART_SET_RTS
V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS));
#endif
}
static unsigned v850e_uart_get_mctrl (struct uart_port *port)
{
/* We don't support DCD or DSR, so consider them permanently active. */
int mctrl = TIOCM_CAR | TIOCM_DSR;
/* We may support CTS. */
#ifdef V850E_UART_CTS
mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0;
#else
mctrl |= TIOCM_CTS;
#endif
return mctrl;
}
static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start)
{
v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
v850e_uart_tx (port);
v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line));
}
static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop)
{
v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
}
static void v850e_uart_start_rx (struct uart_port *port)
{
v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line));
}
static void v850e_uart_stop_rx (struct uart_port *port)
{
v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line));
}
static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl)
{
/* Umm, do this later. */
}
static int v850e_uart_startup (struct uart_port *port)
{
int err;
/* Alloc RX irq. */
err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq,
SA_INTERRUPT, "v850e_uart", port);
if (err)
return err;
/* Alloc TX irq. */
err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq,
SA_INTERRUPT, "v850e_uart", port);
if (err) {
free_irq (V850E_UART_RX_IRQ (port->line), port);
return err;
}
v850e_uart_start_rx (port);
return 0;
}
static void v850e_uart_shutdown (struct uart_port *port)
{
/* Disable port interrupts. */
free_irq (V850E_UART_TX_IRQ (port->line), port);
free_irq (V850E_UART_RX_IRQ (port->line), port);
/* Turn off xmit/recv enable bits. */
V850E_UART_CONFIG (port->line)
&= ~(V850E_UART_CONFIG_TX_ENABLE
| V850E_UART_CONFIG_RX_ENABLE);
/* Then reset the channel. */
V850E_UART_CONFIG (port->line) = 0;
}
static void
v850e_uart_set_termios (struct uart_port *port, struct termios *termios,
struct termios *old)
{
unsigned cflags = termios->c_cflag;
/* Restrict flags to legal values. */
if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8)
/* The new value of CSIZE is invalid, use the old value. */
cflags = (cflags & ~CSIZE)
| (old ? (old->c_cflag & CSIZE) : CS8);
termios->c_cflag = cflags;
v850e_uart_configure (port->line, cflags,
uart_get_baud_rate (port, termios, old,
v850e_uart_min_baud(),
v850e_uart_max_baud()));
}
static const char *v850e_uart_type (struct uart_port *port)
{
return port->type == PORT_V850E_UART ? "v850e_uart" : 0;
}
static void v850e_uart_config_port (struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_V850E_UART;
}
static int
v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser)
{
if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART)
return -EINVAL;
if (ser->irq != V850E_UART_TX_IRQ (port->line))
return -EINVAL;
return 0;
}
static struct uart_ops v850e_uart_ops = {
.tx_empty = v850e_uart_tx_empty,
.get_mctrl = v850e_uart_get_mctrl,
.set_mctrl = v850e_uart_set_mctrl,
.start_tx = v850e_uart_start_tx,
.stop_tx = v850e_uart_stop_tx,
.stop_rx = v850e_uart_stop_rx,
.enable_ms = v850e_uart_nop,
.break_ctl = v850e_uart_break_ctl,
.startup = v850e_uart_startup,
.shutdown = v850e_uart_shutdown,
.set_termios = v850e_uart_set_termios,
.type = v850e_uart_type,
.release_port = v850e_uart_nop,
.request_port = v850e_uart_success,
.config_port = v850e_uart_config_port,
.verify_port = v850e_uart_verify_port,
};
/* Initialization and cleanup. */
static struct uart_driver v850e_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "v850e_uart",
.devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = V850E_UART_MINOR_BASE,
.nr = V850E_UART_NUM_CHANNELS,
.cons = V850E_UART_CONSOLE,
};
static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS];
static int __init v850e_uart_init (void)
{
int rval;
printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME);
rval = uart_register_driver (&v850e_uart_driver);
if (rval == 0) {
unsigned chan;
for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) {
struct uart_port *port = &v850e_uart_ports[chan];
memset (port, 0, sizeof *port);
port->ops = &v850e_uart_ops;
port->line = chan;
port->iotype = SERIAL_IO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
/* We actually use multiple IRQs, but the serial
framework seems to mainly use this for
informational purposes anyway. Here we use the TX
irq. */
port->irq = V850E_UART_TX_IRQ (chan);
/* The serial framework doesn't really use these
membase/mapbase fields for anything useful, but
it requires that they be something non-zero to
consider the port `valid', and also uses them
for informational purposes. */
port->membase = (void *)V850E_UART_BASE_ADDR (chan);
port->mapbase = V850E_UART_BASE_ADDR (chan);
/* The framework insists on knowing the uart's master
clock freq, though it doesn't seem to do anything
useful for us with it. We must make it at least
higher than (the maximum baud rate * 16), otherwise
the framework will puke during its internal
calculations, and force the baud rate to be 9600.
To be accurate though, just repeat the calculation
we use when actually setting the speed. */
port->uartclk = v850e_uart_max_clock() * 16;
uart_add_one_port (&v850e_uart_driver, port);
}
}
return rval;
}
static void __exit v850e_uart_exit (void)
{
unsigned chan;
for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++)
uart_remove_one_port (&v850e_uart_driver,
&v850e_uart_ports[chan]);
uart_unregister_driver (&v850e_uart_driver);
}
module_init (v850e_uart_init);
module_exit (v850e_uart_exit);
MODULE_AUTHOR ("Miles Bader");
MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART");
MODULE_LICENSE ("GPL");